Regex назвал группы захвата в Delphi XE - PullRequest
8 голосов
/ 16 марта 2011

Я построил шаблон соответствия в RegexBuddy, который ведет себя точно так, как я ожидаю. Но я не могу перенести это в Delphi XE, по крайней мере, при использовании последней встроенной версии TRegEx или TPerlRegEx.

В моем реальном коде есть 6 групп захвата, но я могу проиллюстрировать проблему на более простом примере. Этот код дает «3» в первом диалоговом окне, а затем вызывает исключение (индекс -7 за пределами) при выполнении второго диалогового окна.

var
  Regex: TRegEx;
  M: TMatch;
begin
  Regex := TRegEx.Create('(?P<time>\d{1,2}:\d{1,2})(?P<judge>.{1,3})');
  M := Regex.Match('00:00  X1 90  55KENNY BENNY');
  ShowMessage(IntToStr(M.Groups.Count));
  ShowMessage(M.Groups['time'].Value);
end;

Но если я использую только одну группу захвата

Regex := TRegEx.Create('(?P<time>\d{1,2}:\d{1,2})');

В первом диалоговом окне отображается «2», а во втором диалоговом окне показывается ожидаемое время «00:00».

Однако это будет немного ограничивать, если будет разрешена только одна именованная группа захвата, но это не так ... Если я изменю имя группы захвата, например, на "atime".

var
  Regex: TRegEx;
  M: TMatch;
begin
  Regex := TRegEx.Create('(?P<atime>\d{1,2}:\d{1,2})(?P<judge>.{1,3})');
  M := Regex.Match('00:00  X1 90  55KENNY BENNY');
  ShowMessage(IntToStr(M.Groups.Count));
  ShowMessage(M.Groups['atime'].Value);
end;

Я получу «3» и «00:00», как и ожидалось. Есть ли зарезервированные слова, которые я не могу использовать? Я так не думаю, потому что в своем реальном примере я попробовал совершенно случайные имена. Я просто не могу понять, что вызывает такое поведение.

Ответы [ 2 ]

7 голосов
/ 16 марта 2011

Когда pcre_get_stringnumber не находит имя, возвращается PCRE_ERROR_NOSUBSTRING.

PCRE_ERROR_NOSUBSTRING определяется в RegularExpressionsAPI как PCRE_ERROR_NOSUBSTRING = -7.

Некоторое тестирование показывает, что pcre_get_stringnumber возвращает PCRE_ERROR_NOSUBSTRING для каждого имени, которое имеет первую букву в диапазоне от k до z, и этот диапазон зависит от первой буквы в judge. Изменение judge на что-то другое меняет диапазон.

Насколько я понимаю, здесь есть как минимум две ошибки. Один в pcre_get_stringnumber и один в TGroupCollection.GetItem, который должен вызвать правильное исключение вместо SRegExIndexOutOfBounds

5 голосов
/ 23 марта 2011

Ошибка, по-видимому, связана с модулем RegularExpressionsAPI, который упаковывает библиотеку PCRE, или в файлах PCRE OBJ, которые она связывает.Если я запускаю этот код:

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils, RegularExpressionsAPI;

var
  myregexp: Pointer;
  Error: PAnsiChar;
  ErrorOffset: Integer;
  Offsets: array[0..300] of Integer;
  OffsetCount, Group: Integer;

begin
  try
    myregexp := pcre_compile('(?P<time>\d{1,2}:\d{1,2})(?P<judge>.{1,3})', 0, @error, @erroroffset, nil);
    if (myregexp <> nil) then begin
      offsetcount := pcre_exec(myregexp, nil, '00:00  X1 90  55KENNY BENNY', Length('00:00  X1 90  55KENNY BENNY'), 0, 0, @offsets[0], High(Offsets));
      if (offsetcount > 0) then begin
        Group := pcre_get_stringnumber(myregexp, 'time');
        WriteLn(Group);
        Group := pcre_get_stringnumber(myregexp, 'judge');
        WriteLn(Group);
      end;
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  ReadLn;
end.

Он печатает -7 и 2 вместо 1 и 2.

Если я удаляю RegularExpressionsAPI из предложения uses и добавляю модуль pcreиз моего компонента TPerlRegEx , тогда он правильно печатает 1 и 2.

* RegularExpressionsAPI в Delphi XE основан на моем pcre модуле, а RegularExpressionsCore основан нана моем PerlRegEx устройстве.Embarcadero сделал некоторые изменения в обоих подразделениях.Они также скомпилировали свои собственные файлы OBJ из библиотеки PCRE, которые связаны RegularExpressionsAPI.

Я сообщил об этой ошибке как QC 92497

Я также создалотдельный отчет QC 92498 , чтобы запросить TGroupCollection.GetItem вызвать более разумное исключение при запросе именованной группы, которая не существует.(Этот код находится в блоке RegularExpressions, который основан на коде, написанном Винсентом Парреттом, а не мной.)

...