通过阅读How does \G work in .split?后,我快速设置了一个Delphi程序来检查PCRE如何处理这种情况。有趣的是,结果与java案例中的结果不同:
program Project1;
{$APPTYPE CONSOLE}
uses
System.RegularExpressions;
var
SArr: TArray<string>;
S: string;
begin
SArr := TRegex.Split('abcdefghij', '(?<=\G..)',[]);
for S in SArr do
begin
WriteLn(S);
end;
ReadLn;
end.
输出:
ab
cde
fgh
ij
为什么PCRE结果与Java结果不同?如何解释这种行为?
为了确保这不是Delphi错误,我在regex 101中进行了测试,匹配行为似乎相同:https://regex101.com/r/GE6eRI/1
答案 0 :(得分:2)
我想引用Alan Moore:
这个技巧(例如)可以在Java,Perl,.NET和JGSoft中使用,但不适用于PHP(PCRE),Ruby 1.9+或TextMate(都是Oniguruma)
我认为适用于PCRE docs的引用:
但请注意,PCRE对
\G
的解释,作为当前比赛的开始,与Perl's略有不同,后者将其定义为上一场比赛的结束。在Perl中,当先前匹配的字符串为空时,这些可以不同。由于PCRE一次只进行一次匹配,因此无法重现此行为。
在PCRE的后视中似乎\G
令牌处理zero-length匹配问题,因为当\G
匹配后,它会前进一个字符。假设下面是正则表达式:
(?<=\G)
并输入字符串:
abcd
带有全局修饰符的匹配5个位置(参见live demo)。但我们期望匹配一个且只有一个位置,就像Java的行为一样。使用PHP生成与Java相同结果的解决方法是使用\K
和捕获组:
(?<=\K\G(..))
同样,上述任务可以通过以下方式完成:
\G..\K