Zero-Length Mathes:零长度匹配,指的是像 anchor
,word boundary
和 lookaround
这种匹配的是位置,而不是匹配单个字符的正则表达式语法;
anchor
:^
匹配第一个字符之前的位置,$
匹配最后一个字符之后的位置;对于 CRLF (Carriage return / Line feed) 回车和换行字符,Java 把 CRLF 当成不可分割的整体,^
在 CRLF 之后匹配,$
在 CRLF 之前匹配;word boundary
:单词边界,匹配两个字符之间的位置,其中一个是单字字符 (即\w
匹配的字符,[a-zA-Z_0-9]
),另一个是非单字字符;且匹配字符串第一个字符之前的位置和字符串最后一个字符之后的位置 ( 如果是单字字符);\b 匹配单字字符和非单字字符之间的位置 \B 匹配与 \b 相反的情况,不仅匹配单字字符和单字字符之间的位置,也匹配非单字字符和非单字字符之间的位置 \bword\b 匹配 This is a word. \Bword\B 匹配 aworda \B=word 匹配 =word和==word 不匹配 w=word
lookaround
:lookahead
和lookbehind
统称为 lookaround;其中,又分为 Positive 和 Negative ;为什么称它们为零长度匹配呢?因为它们只是匹配位置,不消耗字符,比如说匹配字符 q ,q 后面不能跟着字符 u,那么匹配 u 的时候只是判断有没有字符 u 跟在 q 后面,最终只匹配了字符 q,而不是匹配 qu 两个字符;Positive lookahead:(?=X) 例如:q(?=u) 匹配 quit,首先正则表达式的 token q 匹配了字符 q,下一个字符是 u,与 lookahead 里面的 token u 成功匹配,也就是说 lookahead 在当前位置上成功匹配,然后引擎会回退到字符 u; 回退是什么意思呢? 再来看一个例子: q(?=u)i 匹配 quit,同样的步骤匹配到了字符 u,这时引擎回退到字符 u 继续与后面的 token 进行匹配,而此时正则表达式的 token i 与字符 u 不匹配,导致了匹配失败;事实上,q(?=u)i 匹配不到任何东西,它要求同一个位置能同时匹配字符 u 和字符 i,这显然不可能; Negative lookahead:(?!X) 与(?=X)相反,匹配不到则返回正确;例如:q(?!u) 匹配 quit 失败,匹配 qing 成功; Positive lookbehind:(?<=X) 例如:(?<=f)o 匹配 foot,首先引擎从 lookbehind 和字符串 foot 的第一个字符 f 开始,lookbehind 告诉引擎回退一个字符来匹配 token f,但是因为第一个字符前面没有字符,不能回退,所以匹配失败;继续往前匹配 lookbehind 和字符串的第一个 o,引擎回退到 o 前面的 f,与 lookbehind 匹配成功,这时指针的位置不变,还是在 o 的前面、f 的后面,继续往前匹配 token o 和字符串的第一个 o,匹配成功,最后成功匹配的是第一个字符 o,结束; Negative lookbehind:(?<!X) 与(?<=X)相反,匹配不到则返回正确,例如:(?<!f)o 匹配 foot,匹配成功的是第二个字符 o;
总结:lookahead 匹配了之后指针还在匹配的字符前面,适用于限制某些字符后面跟着什么字符的情况;lookbehind 匹配了之后指针在匹配的字符后面,适用于限制某些字符前面跟着什么字符的情况,如下图:
Atomic group (non-capturing group):原子组 (?>X)
,在匹配了 group 里面的第一个模式 (pattern) 后就返回匹配结果,不能回溯继续匹配后面的模式:
(?>foo|foot)s
只匹配 foos 不匹配 foots;对于 foots,它首先匹配到 foo,但是后面跟着的字符是 t 而不是 s,所以匹配失败,不进行回溯;
(foo|foot)s
匹配 foos 和 foots;对于 foots,它首先匹配到 foo,匹配失败,回溯到 foot 继续匹配,匹配到 foots ;
参考资料:
https://www.regular-expressio...
测试正则表达式的网址:
https://regex101.com/
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。