Как работает \ G в PCRE - PullRequest
0 голосов
/ 16 мая 2018

После прочтения Как работает \ G в .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

1 Ответ

0 голосов
/ 16 мая 2018

Я хотел бы процитировать от Алан Мур :

Этот прием будет работать (например) в Java, Perl, .NET и JGSoft, но не в PHP (PCRE), Ruby 1.9+ или TextMate (оба Oniguruma)

Цитата из PCRE docs , которая, я думаю, применима здесь:

Обратите внимание, однако, что интерпретация \G в PCRE как начало текущего совпадения слегка отличается от Perl, который определяет его как конец предыдущего совпадения. В Perl они могут отличаться, когда ранее согласованная строка была пустой. Поскольку PCRE выполняет только одно сопоставление за раз, он не может воспроизвести это поведение.

Кажется, что \G токен во внешнем виде в PCRE решает проблему соответствия нулевой длины , потому что когда \G совпадает во взгляде, он продвигается на один символ. Предположим, ниже регулярное выражение:

(?<=\G)

и входная строка:

abcd

с глобальным модификатором соответствует 5 позициям (см. live-демо ). Но мы ожидаем совпадения с одной и только одной позицией, например, как ведет себя Java. Обходной путь с PHP для получения того же результата, что и Java, использующий \K вместе с группой захвата:

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

То же самое, указанное выше задание можно выполнить с помощью:

\G..\K
...