\ G如何在PCRE外观中工作

时间:2018-05-16 08:51:59

标签: java regex delphi pcre regex-lookarounds

通过阅读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

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