正面lookbehind vs匹配重置(\ K)正则表达式功能

use*_*951 8 php ruby python regex perl

我只是了解了明显无证 \K Ruby的正则表达式(感谢行为此答案anubhava).此功能(可能名为Keep?)也存在于PHP,Perl和Python正则表达式中.它在其他地方被描述为" 从匹配中丢弃到目前为止匹配的内容 ".

"abc".match(/ab\Kc/)     # matches "c"
Run Code Online (Sandbox Code Playgroud)

这种行为是否与下面使用的正向外观标记相同?

"abc".match(/(?<=ab)c/)  # matches "c"
Run Code Online (Sandbox Code Playgroud)

如果没有,两者有什么不同之处?

Cas*_*yte 7

它更容易看到的区别\K,并(?<=...)String#scan方法.

lookbehind是一个零宽度断言,它不消耗字符,并且从当前位置进行测试(向后):

> "abcdefg".scan(/(?<=.)./)
=> ["b", "c", "d", "e", "f", "g"]
Run Code Online (Sandbox Code Playgroud)

"保持"特征\K (不是锚)定义了模式中的位置,其中到目前为止所有匹配的位置都从匹配结果中移除.但是,匹配所有字符之前\K消耗掉,他们只是不会出现在结果中:

> "abcdefg".scan(/.\K./)
=> ["b", "d", "f"]
Run Code Online (Sandbox Code Playgroud)

行为与没有相同\K:

> "abcdefg".scan(/../)
=> ["ab", "cd", "ef"]
Run Code Online (Sandbox Code Playgroud)

除了\K从结果中删除之前的字符.

一个有趣的用途\K是模拟可变长度的lookbehind,这在Ruby中是不允许的(对于PHP和Perl也是如此),或者避免创建唯一的捕获组.例如,(?<=a.*)f.可以使用\K以下方法实现:

> "abcdefg".match(/a.*\Kf./)
=> #<MatchData "fg">
Run Code Online (Sandbox Code Playgroud)

另一种方法是编写/a.*(f.)/,但\K避免了创建捕获组的需要.

请注意,该\K功能也存在于python 正则表达式模块中,即使这个功能允许可变长度的lookbehinds.

  • 我不了解 Ruby,但是 Perl 中的 `\K` 比 `(?&lt;=...)` 更快。/// 人们通常专门使用 `\K` 来避免使用捕获组,因此您建议相反的建议很奇怪。 (2认同)