在使用“”和“?”时要注意,由于这些字符可能匹配0个字符,因此它们允许什么都不匹配。例如,正则表达式/a*/实际上与字符串“bbbb”匹配,因为这个字符串含有0个a。
非贪婪的重复
表10-3中列出的匹配重复字符是尽可能多地匹配,而且允许后续的正则表达式继续匹配。因此,我们称之为“贪婪的”匹配。我们同样可以使用正则表达式进行非贪婪匹配。只须在待匹配的字符后跟随一个问号即可:“??”、“+?”、“*?”或“{1,5}?”。比如,正则表达式/a+/可以匹配一个或多个连续的字母a。当使用“aaa”作为匹配字符串时,正则表达式会匹配它的三个字符。但是/a+?/也可以匹配一个或多个连续字母a,但它是尽可能少地匹配。我们同样将“aaa”作为匹配字符串,但后一个模式只能匹配第一个a。
使用非贪婪的匹配模式所得到的结果可能和期望并不一致。考虑以下正则表达式/a+b/,它可以匹配一个或多个a,以及一个b。当使用“aaab”作为匹配字符串时,它会匹配整个字符串。现在再试一下非贪婪匹配的版本/a+?b/,它匹配尽可能少的a和一个b。当用它来匹配“aaab”时,你期望它能匹配一个a和最后一个b。但实际上,这个模式却匹配了整个字符串,和该模式的贪婪匹配一模一样。这是因为正则表达式的模式匹配总是会寻找字符串中第一个可能匹配的位置。由于该匹配是从字符串的第一个字符开始的,因此在这里不考虑它的子串中更短的匹配。
1.4选择、分组和引用
正则表达式的语法还包括指定选择项、子表达式分组和引用前一子表达式的特殊字符。字符“|”用于分隔供选择的字符。例如,/ab|cd|ef/可以匹配字符串“ab”,也可以匹配字符串“cd”,还可以匹配字符串“ef”。/\d{3}|[a-z]{4}/匹配的是三位数字或者四个小写字母。
注意,选择项的尝试匹配次序是从左到右,直到发现了匹配项。如果左边的选择项匹配,就忽略右边的匹配项,即使它产生更好的匹配。因此,当正则表达式/a|ab/匹配字符串“ab”时,它只能匹配第一个字符。
表10-4:正则表达式的选择、分组和引用字符
字符
含义
|
选择,匹配的是该符号左边的子表达式或右边的子表达式
(...)
组合,将几个项组合为一个单元,这个单元可通过“*”、“+”、“?”和“|”等符号加以修饰,而且可以记住和这个组合相匹配的字符串以供此后的引用使用
(?:...)
只组合,把项组合到一个单元,但不记忆与该组相匹配的字符
\n
和第n个分组第一次匹配的字符相匹配,组是圆括号中的子表达式(也有可能是嵌套的),组索引是从左到右的左括号数,“(?:”形式的分组不编码
1.5指定匹配位置
正如前面所介绍的,正则表达式中的多个元素才能够匹配字符串的一个字符。例如,\s匹配的只是一个空白符。还有一些正则表达式的元素匹配的是字符之间的位置,而不是实际的字符。
最常用的锚元素是^,它用来匹配字符串的开始,锚元素$用以匹配字符串的结束。
表10-5:正则表达式中的锚字符
字符
含义
^
匹配字符串的开头,在多行检索中,匹配一行的开头
$
匹配字符串的结尾,在多行检索中,匹配一行的结尾
\b
匹配一个单词的边界,简言之,就是位于字符\w和\W之间的位置,或位于字符\w和字符串的开头或者结尾之间的位置(但需要注意,[\b]匹配的是退格符)
\B
匹配非单词边界的位置
(?=p)
零宽正向先行断言,要求接下来的字符都与p匹配,但不能包括匹配p的那些字符
(?!p)
零宽负向先行断言,要求接下来的字符不与p匹配
1.6修饰符