分组语法 捕获
(exp)
:匹配exp
,并捕获文本到自动命名的组里
(?<name>exp)
:匹配exp
,并捕获文本到名称为name
的组里,也可以写成(?'name'exp)
(?:exp)
:匹配exp
,不捕获匹配的文本
位置指定
(?=exp)
匹配exp
前面的位置
(?<=exp)
匹配exp
后面的位置
(?!exp)
匹配后面跟的不是exp
的位置
(?<!exp)
匹配前面不是exp
的位置
关于位置指定
(?=exp)
也叫零宽先行断言,它匹配文本中的某些位置,这些位置的后面能匹配给定的后缀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
的单词。但是如果多做测试(或者你思维足够敏锐,直接就观察出来了),你会发现,如果q出现在单词的结尾的话,像Iraq,Benq,这个表达式就会出错。这是因为[^u]
总是匹配一个字符,所以如果q
是单词的最后一个字符的话,后面的[^u]将会匹配q后面的单词分隔符(可能是空格,或者是句号或其它的什么),后面的\w*\b
将会匹配下一个单词,于是\b\w*q[^u]\w*\b
就能匹配整个Iraq fighting
。负向位置指定能解决这样的问题,因为它只匹配一个位置,并不消费任何字符。现在,我们可以这样来解决这个问题:\b\w*q(?!u)\w*\b
。
零宽负向先行断言(?!exp)
,只会匹配后缀exp
不存在的位置。\d{3}(?!\d)
匹配三位数字,而且这三位数字的后面不能是数字。