前言
对于正则表达式,相信很多人都知道,但是很多人的第一感觉就是难学,因为看第一眼时,觉得完全没有规律可寻,而且全是一堆各种各样的特殊符号,完全不知所云。
其实只是对正则不了解而以,了解了你就会发现,原来就这样啊正则所用的相关字符其实不多,也不难记,更不难懂,唯一难的就是组合起来之后,可读性比较差,而且不容易理解。
本文旨在让大家对正则有一个基本的了解,能看得懂简单的正则表达式,写得出简单的正则表达式,用以满足日常开发中的需求即可。
0\d{2}-\d{8}|0\d{3}-\d{7}
先来一段正则,如果你对正则不了解,是不是完全不知道这一串字符是什么意思?这不要紧文章会详细解释每个字符的含义的。
1.1 什么是正则表达式
正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具与产品,而正则就是这个模具,定义一种规则去匹配符合规则的字符。
1.2 常用的正则匹配工具
在线匹配工具:https://tool.oschina.net/regex/
正则匹配软件:McTracer、RegexBuddy(如下)
(1)IGNORECASE 忽略大小写模式
匹配时忽略大小写
默认情况下,正则表达式是要区分大小写的
(2)SINGLEINE 单行模式
整个文本看作一个字符串,只有一个开头,一个结尾
使小数点"."可以匹配包含换行符(\n) 在内的任意字符
(3)MULTILINE 多行模式
每行都是一个字符串,都有开头和结尾
在指定了MULTLINE之后,如果需要仅匹配字符串开始和结束为止,可以使用\A和\Z
1.3 使用流程
(1).分析所要匹配的数据,写出测试用的典型数据
(2)在工具软件中进行匹配测试
(3)在程序中调用通过测试的正则表达式
1.4 正则表达式可使用范围
大部分编程语言、数据库、文本编辑器、开发环境都支持正则表达式,如:
eclipse、Notepad++、Editplus、UltraEdit、Mysql5.5以上、Oracle10g以上
正则字符介绍
2.1 元字符介绍
边界匹配器
本组标记匹配的不是字符,而是位置,符合某种条件的位置
"^"
:^会匹配行或者字符串的起始位置,有时还会匹配整个文档的起始位置。
"$"
:$会匹配行或字符串的结尾
"\b"
:不会消耗任何字符只匹配一个位置,常用于匹配单词边界。
如:我想从字符串中"This is Regex"匹配单独的单词 “is” 正则就要写成 “\bis\b” , \b 不会匹配is 两边的字符,但它会识别is 两边是否为单词的边界
预定义字符类
能够与’多种字符’ 匹配的表达式,注意区分大小写,大写是相反的意思
"\d"
:任意一个数字,0~9中任意一个。
例如要匹配一个固定格式的电话号码以0开头前4位后7位,如0737-5686123 正则:^0\d\d\d-\d\d\d\d\d\d\d$ 这里只是为了介绍"\d"字符,实际上有更好的写法会在下面介绍。
"\w"
:任意一个字母或数字或下划线,也就是A ~ Z,a ~ z,0 ~ 9,_中任意一个。
例如我要匹配"a2345BCD__TTz" 正则:"\w+" 这里的"+"字符为一个量词指重复的次数,稍后会详细介绍。
"\s"
:包括空格、制表符、换行符等空白字符的其中任意一个。
例如字符 “a b c” 正则:"\w\s\w\s\w" 一个字符后跟一个空格,如有字符间有多个空格直接把"\s" 写成 “\s+” 让空格重复
"."
: 可以匹配除了换行符以外任意一个字符。如果要匹配包括“\n”在内的所有字符,用[\s\S]。
这个算是"\w"的加强版了"\w"不能匹配 空格 如果把字符串加上空格用"\w"就受限了,看下用 “.“是如何匹配字符"a23 4 5 B C D__TTz” 正则:”.+"
自定义字符类
[]方括号匹配方式,能够匹配方括号中任意一个字符。正则表达式的特殊符号,被包含到中括号中,则失去特殊意义,除了"^"
,"-"
之外,标准字符集合除了小数点外,如果包含于中括号,自定义字符集合将包含该集合。比如[\d.-+]将匹配:数字、小数点、-、+
"[abc]"
:字符组 匹配包含括号内元素的字符
这个比较简单了只匹配括号内存在的字符,还可以写成[a-z]匹配a至z的所以字母就等于可以用来控制只能输入英文了。如:
[ab5@] 匹配"a"或"b"或"5"或“@”
[^abc] 匹配"a",“b”,“c"之外的任意一个字符
[f-k] 匹配"f”-“k"之间的任意一个字母
[^A-F0-3] 匹配"A” ~ “F”,“0” ~ “3”,之外的任意一个字符
几种反义
写法很简单改成大写就行了,意思与原来的相反,这里就不举例子了
"\W"
:匹配任意不是字母,数字,下划线 的字符
"\S"
:匹配任意不是空白符的字符
"\D"
:匹配任意非数字的字符
"\B"
:匹配不是单词开头或结束的位置
"[^abc]"
:匹配除了abc以外的任意字符
2.2 量词介绍
修饰匹配次数的特殊符号,匹配次数中的贪婪模式(匹配字符越多越好,默认),匹配次数中的非贪婪模式(匹配字符越少越好,修饰匹配次数的特殊符号后再加上一个"?"号)
先解释关于量词所涉及到的重要的三个概念
贪婪(贪心) 如"*"
字符 :
贪婪量词会首先匹配整个字符串,尝试匹配时,它会选定尽可能多的内容,如果 失败则回退一个字符,然后再次尝试回退的过程就叫做回溯,它会每次回退一个字符,直到找到匹配的内容或者没有字符可以回退。相比下面两种贪婪量词对资源的消耗是最大的。
懒惰(勉强) 如 "?"
:
懒惰量词使用另一种方式匹配,它从目标的起始位置开始尝试匹配,每次检查一个字符,并寻找它要匹配的内容,如此循环直到字符结尾处。
占有 如"+"
:
占有量词会覆盖事个目标字符串,然后尝试寻找匹配内容 ,但它只尝试一次,不会回溯,就好比先抓一把石头,然后从石头中挑出黄金。
"*"
:(贪婪) 重复零次或更多,相当于{0,}
例如"aaaaaaaa" 匹配字符串中所有的a 正则: “a*” 会出到所有的字符"a"
"+"
:(懒惰) 重复一次或更多次,相当于{1,}
例如"aaaaaaaa" 匹配字符串中所有的a 正则: “a+” 会取到字符中所有的a字符, “a+“与"a*“不同在于”+“至少是一次而”*” 可以是0次,稍后会与”?"字符结合来体现这种区别
"?"
:(占有) 重复零次或一次,相当于{0,1}
例如"aaaaaaaa" 匹配字符串中的a 正则 : “a?” 只会匹配一次,也就是结果只是单个字符a
"{n}"
:重复n次
例如从"aaaaaaaa" 匹配字符串的a 并重复3次 正则: “a{3}” 结果就是取到3个a字符 “aaa”;
"{n,m}"
:重复n到m次
例如正则 “a{3,4}” 将a重复匹配3次或者4次 所以供匹配的字符可以是三个"aaa"也可以是四个"aaaa" 正则都可以匹配到
"{n,}"
:重复n次或更多次
与{n,m}不同之处就在于匹配的次数将没有上限,但至少要重复n次 如 正则"a{3,}" a至少要重复3次
把量词了解了之后之前匹配电话号码的正则现在就可以改得简单点了^0\d\d\d-\d\d\d\d\d\d\d 可以改为 “0\d+−\d7”。
这样写还不够完美如果因为前面的区号没有做限定,以至于可以输入很多们,而通常只能是3位或者4位,
现在再改一下 "^0\d{2,3}-\d{7}"如此一来区号部分就可以匹配3位或者4位的了
2.3 懒惰限定符
"*?"
:重复任意次,但尽可能少重复
如 “acbacb” 正则 “a.*?b” 只会取到第一个"acb" 原本可以全部取到但加了限定符后,只会匹配尽可能少的字符 ,而"acbacb"最少字符的结果就是"acb"
"+?"
:重复1次或更多次,但尽可能少重复
与上面一样,只是至少要重复1次
"??"
:重复0次或1次,但尽可能少重复
如 “aaacb” 正则 “a.??b” 只会取到最后的三个字符"acb"
"{n,m}?"
:重复n到m次,但尽可能少重复
如 “aaaaaaaa” 正则 “a{0,m}” 因为最少是0次所以取到结果为空
"{n,}?"
:重复n次以上,但尽可能少重复
如 “aaaaaaa” 正则 “a{1,}” 最少是1次所以取到结果为 “a”
正则捕获分组
先了解在正则中捕获分组的概念,其实就是一个括号内的内容 如 "(\d)\d"
而"(\d)"
这就是一个捕获分组,可以对捕获分组进行 后向引用 (如果后而有相同的内容则可以直接引用前面定义的捕获组,以简化表达式) 如(\d)\d\1
这里的"\1"就是对"(\d)"
的后向引用
那捕获分组有什么用呢看个例子就知道了
如 “zery zery” 正则 \b(\w+)\b\s\1\b
所以这里的"\1"所捕获到的字符也是 与(\w+)
一样的"zery",为了让组名更有意义,组名是可以自定义名字的
"\b(?<name>\w+)\b\s\k<name>\b"
用"?<name>"
就可以自定义组名了而要后向引用组时要记得写成 "\k<name>"
;自定义组名后,捕获组中匹配到的值就会保存在定义的组名里
选择符和分组
"()"
:捕获组,在被修饰匹配次数的时候,括号中的表达式可以作为整体被修饰,取匹配结果的时候,括号中的表达式匹配到的内容可以被单独得到,每一对括号会分配一个编号,使用()的铺货根据左括号的顺序从1开始,自动编号,捕获元素编号为零的第一个捕获是由整个正则表达式模式匹配的文本
"|"
:分支,左右两边表达式之间"或"关系,匹配左边或者右边
捕获分组常有的用法
"(exp)"
:匹配exp,并捕获文本到自动命名的组里
"(?<name>exp)"
:匹配exp,并捕获文本到名称为name的组里
"(?:exp)"
:匹配exp,不捕获匹配的文本,也不给此分组分配组号
以下为零宽断言
"(?=exp)"
:匹配exp前面的位置
如 “How are you doing” 正则"(?.+(?=ing))" 这里取ing前所有的字符,并定义了一个捕获分组名字为 “txt” 而"txt"这个组里的值为"How are you do";
"(?<=exp)"
: 匹配exp后面的位置
如 “How are you doing” 正则"(?(?<=How).+)" 这里取"How"之后所有的字符,并定义了一个捕获分组名字为 “txt” 而"txt"这个组里的值为" are you doing";
"(?!exp)"
:匹配后面跟的不是exp的位置
如 “123abc” 正则 "\d{3}(?!\d)"匹配3位数字后非数字的结果
"(?<!exp)"
:匹配前面不是exp的位置
如 “abc123 " 正则 “(?<![0-9])123” 匹配"123"前面是非数字的结果也可写成”(?!<\d)123"
Java正则表达式介绍
Java正则表达式依赖包于 java.util.regex包下。
核心类Pattern.java:
//##静态方法
//编译正则表达式
Pattern.complie()
//编译正则表达式,并进行匹配全字符串,返回boolean值
Pattern.matchers(String regex, String str)
核心类Matcher.java
通过解释Pattern对character sequence执行匹配操作的引擎
//##普通方法
//尝试将整个字符序列与该模式匹配
boolean matches()
//从字符串开头向前匹配,直到匹配不符合停止(查找下一个匹配对象)
boolean find()
//这个方法必须和find方法配合使用,单独使用就会报错且group()和gourp(0)是匹配第一个符合的子串
///返回匹配对象对应分组的匹配结果
String group(int group)
//替换整个字符序列中与该模式匹配的子串
repalceAll();
示例
//全匹配
//表达式对象
//建立正则表达式,并启用相关模式
//Pattern p = Pattern.complie();
Pattern p = Pattern.complie("\\w+");
//Matcher对象
//匹配str字符串
//Macher m = p.matcher(str);
Matcher m = p.matcher("as123435");
//尝试将整个字符序列与该模式匹配
System.out.println(m.matches());
//分组
Pattern p = Pattern.complie("\\w+");
Matcher m = p.matcher("as1234&&35");
while(m.find()){
System.out.println(m.gourp());
}
//替换
Pattern p = Pattern.complie("[0-9]");
Matcher m = p.matcher("as**1234**35");
System.out.println(m.replaceAll("#"));
//分割
String str="asdf234gffs35";
String[] arr = str.split("\\d+");
System.out.println(Arrays.toString(arr));