1、表达式基础
1.1 句点符号
假设在玩英文拼字游戏,想要找出三个字母的单词,而且这些单词必须以“t”字母开头,以“n”字母结束。要构造出这个正则表达式,可以使用一个通配符——句点符号“.”。这样,完整的表达式就是“t.n”,它匹配“tan”、“ten”、“tin”和“ton”,还匹配“t#n”、“tpn”甚至“t n”,还有其他许多无意义的组合。这是因为句点符号匹配所有字符,包括空格、Tab字符甚至换行符。
1.2 方括号符号
为了解决句点符号匹配范围过于广泛这一问题,你可以在方括号(“[]”)里面指定看来有意义的字符。此时,只有方括号里面指定的字符才参与匹配。也就是说,正则表达式“t[aeio]n”只匹配“tan”、“Ten”、“tin”和“ton”。但“Toon”不匹配,因为在方括号之内只能匹配单个字符。
此外,方括号内还可以用“-”表示跨度,如“[a-g]”匹配字母表中a到g的小写字母,“[1-9]”匹配1到9的数字。
可以使用“&&”取交集,比如“[1-9&&[^456]]”,匹配1到9中除了4、5、6以外的数字。
1.3 “或”符号
如果除了上面匹配的所有单词之外,还想要匹配“toon”,那么,你可以使用“|”操作符。“|”操作符的基本意义就是“或”运算。要匹配“toon”,使用“t(a|e|i|o|oo)n”正则表达式。这里不能使用方扩号,因为方括号只允许匹配单个字符;这里必须使用圆括号“()”。圆括号还可以用来分组。
1.4 表示匹配次数的符号
符号 | 意义 |
---|---|
? | 0次或1次 |
+ | 1次或多次,即至少1次 |
* | 0次或多次,即任意多次 |
{n} | 恰好n次 |
{n,m} | n次到m次 |
假设我们要在文本文件中搜索美国的社会安全号码。这个号码的格式是999-99-9999
。用来匹配它的正则表达式如下图所示。
在正则表达式中,连字符(“-”)有着特殊的意义,它表示一个范围,比如从0到9。因此,匹配社会安全号码中的连字符号时,它的前面要加上一个转义字符“\”。
假设进行搜索的时候希望连字符号可以出现,也可以不出现——即,999-99-9999
和999999999
都属于正确的格式。这时,可以在连字符号后面加上“?”数量限定符号,如下图所示:
1.5 “否”符号
“”符号称为“否”符号。如果用在方括号内,“”表示不想要匹配的字符。例如,下图的正则表达式匹配所有单词,但以“X”字母开头的单词除外。
1.6 圆括号
1.6.1 限定量词作用的范围
例
(cat)? 匹配0个或1个“cat”
(cat)+ 匹配1个或多个“cat”
1.6.2 限定多选结构的范围
例
(cat|dog) 匹配“cat”或“dog”
1.6.3 分组捕获
位于圆括号之间的模式匹配的内容都会被捕获,当模式中有嵌套的圆括号时,变量的编号会按照圆开括号出现的位置一次进行。
例
(A-Za-z)((-)\d{2})匹配”A22-33”时,匹配情况如下:
第一个出现的圆括号中的正则表达式为:A-Za-z
匹配结果Group 1: A22
第二个出现的圆括号中的正则表达式为:\d{2}
匹配结果Group 2: 22
第三个出现的圆括号中的正则表达式为:(-)\d{2}
匹配结果Group 3: -33
第四个出现的圆括号中的正则表达式为:-
匹配结果Group 4: -
1.6.4 分组不捕获
当圆括号与“?:”组合使用时,表示非捕获型分组。圆括号的内容不作为捕获对象,当圆括号中的内容不是想捕获的对象时,采用非捕获圆括号可以提高匹配效率。
例
(\w(?:\d{2}))((?:-)\d{2})匹配” A22-33”情况如下:
Group 1: A22
Group 2: -33
注:\d{2}匹配的”22”没有被捕获,-匹配的“-”也没有被捕获。
1.6.5 反向引用捕获文本
例
([ab])\1,圆括号内的“[ab]” 可以匹配“a”或“b”,后面的“\1”代表,如果前面匹配的文本引用。如果捕获组匹配到“a”,那么反向引用也就只能匹配“a”,同理,如果捕获组匹配到的是“b”,那么反向引用也就只能匹配“b”。由于后面反向引用“\1”的限制,要求必须是两个相同的字符,在这里也就是“aa”或者“bb”才能匹配成功。
1.6.6 前瞻
当圆括号与“?=”组合使用时,表示前瞻,代表该表达式会作为匹配校验,但不会出现在匹配结果字符串里面。
例
(John) (?=Resig)匹配情况如下:
John:不匹配,因为后面没有跟着Resig
John Backus:不匹配,后面跟着的不是Resig
John Reisg:匹配,John后面跟着Resig。但是匹配的结果是“John”而不是“John Reisg”。
1.7 预定义字符
符号 | 意义 |
---|---|
\d | 数字字符:[0-9] |
\D | 非数字字符 |
\s | 空白字符:[\t\n\x0B\f\r] |
\S | 非空白字符 |
\w | 单词字符:[a-zA-Z_0-9] |
\W | 非单词字符 |
1.8 边界匹配字符
符号 | 意义 |
---|---|
^ | 行首 |
$ | 行尾 |
\b | 单词边界 |
\B | 非单词边界 |
\A | 输入的开头 |
\G | 上一个匹配的结尾 |
\Z | 输入的结尾,仅用于最后的结束符(如果有的话) |
\z | 输入的结尾 |
1.9 匹配模式
正则表达式有三种匹配模式:
- 贪婪(greedy)
- 勉强(reluctant)
- 侵占(possessive)
贪婪 | 勉强 | 侵占 | 意义 |
---|---|---|---|
X? | X?? | X?+ | 匹配 X 零次或一次 |
X* | X*? | X*+ | 匹配 X 零次或多次 |
X+ | X+? | X++ | 匹配 X 一次或多次 |
X{n} | X{n}? | X{n}+ | 匹配 X n 次 |
X{n,} | X{n,}? | X{n,}+ | 匹配 X 至少 n 次 |
X{n,m} | X{n,m}? | X{n,m}+ | 匹配 X 至少 n 次,但不多于 m 次 |
例
假定要分析的字符串是:xfooxxxxxxfoo
.*foo
(贪婪模式):
模式分为子模式p1(.*)和子模式p2(foo)两个部分。其中p1中的量词匹配方式使用默认方式(贪婪型)。 匹配开始时,吃入所有字符xfooxxxxxxfoo去匹配子模式p1。匹配成功,但这样以来就没有了字符串去匹配子模式p2。本轮匹配失败;第二轮:减少p1部分的匹配量,吐出最后一个字符, 把字符串分割成xfooxxxxxxfo
和o
两个子字符串s1和s2。 s1匹配p1, 但s2不匹配p2。本轮匹配失败;第三轮,再次减少p1部分匹配量,吐出两个字符,字符串被分割成xfooxxxxxxfo
和oo
两部分。结果同上。第四轮,再次减少p1匹配量, 字符串分割成xfooxxxxxx
和foo
两个部分,,这次s1/s2分别和p1/p2匹配。停止尝试,返回匹配成功。-
.*?foo
(勉强模式):最小匹配方式。第一次尝试匹配, p1由于是0或任意次,因此被忽略,用字符串去匹配p2,失败;第二次,读入第一个字符x,尝试和p1匹配,,匹配成功;字符串剩余部分
fooxxxxxxfoo
中前三个字符和p2也是匹配的。因此,停止尝试,返回匹配成功。在这种模式下,如果对剩余字符串继续去寻找和模式相匹配的子字符串,还会找到字符串末尾的另一个xfoo
,而在贪婪模式下,由于第一次匹配成功的子串就已经是所有字符,因此不存在第二个匹配子串。 -
.*+foo
(侵占模式):也叫占用模式。匹配开始时读入所有字符串,和p1匹配成功, 但没有剩余字符串去和p2匹配。因此,匹配失败。返回。
简单地说,贪婪模式和占有模式相比, 贪婪模式会在只有部分匹配成功的条件下,依次从多到少减少匹配成功部分模式的匹配数量,将字符留给模式其他部分去匹配;而占用模式则是占有所有能匹配成功部分,绝不留给其他部分使用。
占用模式目前只有java支持,通常比较少用。
2、Java实例
JDK中与正则表达式相关的类位于java.util.regex
包下。有两个类Pattern
和Matcher
。
String regex = "((A+)(B(C)))";
String input = "ABC-AABC-AAAAABCD";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
int groupCount = matcher.groupCount();
// regex被圆括号分为四组,按照括号的出现位置,分别为:((A+)(B(C)))、(A+)、(B(C))、(C)
// 匹配的时候,还是按照A+BC 去搜索,只不过,每次匹配成功后,会将搜到的字符串按照上面的四组规则分为四个子串,存储起来
while (matcher.find()) {
System.out.print("匹配结果:");
for (int i = 0; i < groupCount; i++) {
System.out.print("group" + i + ":" + matcher.group(i) + "\t");
}
System.out.println();
}
输出:
匹配结果:group0:ABC group1:ABC group2:A group3:BC
匹配结果:group0:AABC group1:AABC group2:AA group3:BC
匹配结果:group0:AAAAABC group1:AAAAABC group2:AAAAA group3:BC