位置指定
接下来的四个用于查找在某些内容之前后者之后的东西,就像\b,^,$这样,它也被称为零宽断言。用例子来说明:
(?=exe)也叫零宽先行断言,它匹配文本中的某些位置,这些位置的后面能匹配给定的后缀exp。比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如果在查找I'm singing while you're dancing.时,它会匹配sing和danc。
(?<=exp)也叫零宽先行断言,它匹配文本中的某些位置,这些位置的签名能给定的前缀exp。比如(?<=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading。
如果你想要给一个很长的数字中每三位间加一个逗号(从右边加起),你可以这样查找需要在前面和里面添加逗号的部分:((?<=\d)\d{3})*\b。
(?<=\s)\d+(?=\s)匹配以空白符间隔的数字,这个例子同时使用了前缀和后缀
负向位置指定
如果我们只是想要确保某个字符没有出现,但并不想去匹配它时怎么办?例如,如果我们想查找一个单词,它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样:\b\w*q[^u]\w*\b匹配包含后面不是字母u的字母q的单词。但是这个表达式是有问题的,[^u]匹配一个字符,如果q出现在句子的结尾比如benq,这样句尾的逗号就会被匹配到,然后就会出现错误,[^u]可以匹配任意字符(空格,逗号,句号等)。负向位指定就可以解决这样的问题,因为它只匹配一个位置,并不消费任何字符。所以我们匹配可以用这样的正则表达式:\b\w*q(?!u)\w*\b。
零宽负向先行断言(?!exp),只会匹配后缀exp不存在的位置。同理,我们可以用(?<!exp),零宽负向后行断言来查找前缀exp不存在的位置
一个更复杂的例子:(?<=<(\w+)>).*(?=<\/\1>)匹配不包含属性的简单HTML标签内里的内容。(<?(\w+)>)指定了这样的前缀:被尖括号括起来的单词(比如可能是<b>),然后是.*(任意的字符串),最后是一个后缀(?=<\/\1>)。注意后缀里的\/,它用到了前面提过的字符转义;\1则是一个反向引用,引用的正是捕获的第一组,前面的(\w+)匹配的内容,这样如果前缀实际上是<b>的话,后缀就是</b>了。整个表达式匹配的是<b>和</b>之间的内容(不包括前缀和后缀本身)。
注释
小括号的另一种用途是能过语法(?#comment)来包含注释。要包含注释的话,最好是启用“忽略模式里的空白符”选项,这样在编写表达式时能任意的添加空格,Tab,换行,而实际使用时这些都将被忽略。启用这个选项后,在#后面到这一行结束的所有文本都将被当成注释忽略掉。例如,我们可以把上一个表达式写成这样:
(?<= # 查找前缀,但不包含它
<(\w+)> # 查找尖括号括起来的字母或数字(标签)
) # 前缀结束
.* # 匹配任意文本
(?= # 查找后缀,但不包含它
<\/\1> # 查找尖括号括起来的内容:前面是一个"/",后面是先前捕获的标签
) # 后缀结束
贪婪与懒惰
当正则表达式中包含很多重复的量词,通常是匹配尽可能多的字符。考虑如下的表达式:a.*b,它将会匹配最长以a开始,以b结束的字符串。如果用它来搜索aabab的话,那么它会搜索到整个字符串而不是ab或者aab。这便被称为贪婪匹配。
那么很容易理解,懒惰匹配就是尽可能少的匹配。只需要在贪婪模式的后面加上一个?就可以。这样.*?就意味着匹配任意数量的最少的重复。如果用它来匹配aabab的话,它匹配aab和ab。
懒惰量词
*? |
复任意次,但尽可能少重复 |
+? |
复1次或更多次,但尽可能少重复 |
?? |
复0次或1次,但尽可能少重复 |
{n,m}? |
复n到m次,但尽可能少重复 |
{n,}? |
复n次以上,但尽可能少重复 |
一些没有介绍到的表达式
\a |
报警字符(打印它的效果是电脑嘀一声) |
\b |
通常是单词分界位置,但如果在字符类里使用代表退格 |
\t |
制表符,Tab |
\r |
回车 |
\v |
竖向制表符 |
\f |
换页符 |
\n |
换行符 |
\e |
Escape |
\0nn |
ASCII代码中八进制代码为nn的字符 |
\xnn |
ASCII代码中十六进制代码为nn的字符 |
\unnnn |
Unicode代码中十六进制代码为nnnn的字符 |
\cN |
ASCII控制字符。比如\cC代表Ctrl+C |
\A |
字符串开头(类似^,但不受处理多行选项的影响) |
\Z |
字符串结尾或行尾(不受处理多行选项的影响) |
\z |
字符串结尾(类似$,但不受处理多行选项的影响) |
\G |
当前搜索的开头 |
\p{name} |
Unicode中命名为name的字符类,例如\p{IsGreek} |
(?>exp) |
贪婪子表达式 |
(?<x>-<y>exp) |
平衡组 |
(?-<y>exp) |
平衡组 |
(?im-nsx:exp) |
在子表达式exp中改变处理选项 |
(?im-nsx) |
为表达式后面的部分改变处理选项 |
(?(exp)yes|no) |
把exp当作零宽正向先行断言,如果在这个位置能匹配,使用yes作为此组的表达式;否则使用no |
(?(exp)yes) |
同上,只是使用空表达式作为no |
(?(name)yes|no) |
如果命名为name的组捕获到了内容,使用yes作为表达式;否使用no |
(?(name)yes) |
同上,只是使用空表达式作为no |
评论