【问题标题】:How does \G work in PCRE lookbehinds\G 如何在 PCRE 后视中工作
【发布时间】:2018-10-26 05:47:19
【问题描述】:

读完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 错误,我在正则表达式 101 中进行了测试,匹配行为似乎相同:https://regex101.com/r/GE6eRI/1

【问题讨论】:

  • 根据我的经验,'(?&lt;=\G..)' 仅适用于 Java 正则表达式,这就是为什么我说我不会依赖这种模式。幸运的是,有一些方法可以解决它(例如匹配 /../g 等)。
  • 似乎\G 的第一次调用在它应该匹配的下一个位置前进,否则使用\K 影响这个指针不应该改变任何东西(?&lt;=\K\G..)
  • 我鼓励你添加java标签,因为它是一种口味间的比较。
  • @revo 添加 Java 和 regex-lookarounds。我不确定 java 标签(因为我的问题没有使用任何 java 代码)和 delphi 标签(因为它只是用来显示 pcre 行为),但包含两者似乎是有意义的。跨度>

标签: java regex delphi pcre regex-lookarounds


【解决方案1】:

我想引用Alan Moore:

这个技巧(例如)在 Java、Perl、.NET 和 JGSoft 中有效,但在 PHP (PCRE)、Ruby 1.9+ 或 TextMate(两者都是 Oniguruma)中无效

来自PCRE docs 的引用我认为适用于这里:

但是请注意,PCRE 将\G 解释为当前匹配的开始,与 Perl 的解释略有不同,Perl 将其定义为上一个匹配的结束。在 Perl 中,当先前匹配的字符串为空时,这些可能会有所不同。因为 PCRE 一次只进行一次匹配,所以它无法重现这种行为。

似乎\G 标记在 PCRE 的后视处理中解决了 zero-length 匹配问题,因为当 \G 在后视中匹配时,它会前进一个字符。假设下面的正则表达式:

(?<=\G)

和输入字符串:

abcd

带有全局修饰符的它匹配 5 个位置(参见 live demo)。但是我们希望匹配一个且只有一个位置,就像 Java 的行为方式一样。使用 PHP 产生与 Java 相同结果的解决方法是使用 \K 和捕获组:

(?<=\K\G(..))

同样的,上面的任务可以用:

\G..\K

【讨论】:

    猜你喜欢
    • 2022-11-17
    • 1970-01-01
    • 2012-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多