8

我在 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”。有不能使用的保留字吗?我不这么认为,因为在我的真实示例中,我尝试了完全随机的名称。我只是无法弄清楚导致这种行为的原因。

4

2 回答 2

7

pcre_get_stringnumber没有找到名字时,PCRE_ERROR_NOSUBSTRING返回。

PCRE_ERROR_NOSUBSTRING在 RegularExpressionsAPI 中定义为PCRE_ERROR_NOSUBSTRING = -7.

一些测试表明,对于第一个字母在to范围内的每个名称的pcre_get_stringnumber返回值,并且该范围取决于. 更改为其他内容会更改范围。PCRE_ERROR_NOSUBSTRINGkzjudgejudge

正如我所看到的,这里至少涉及两个错误。TGroupCollection.GetItem 中的一个pcre_get_stringnumber和一个需要引发适当的异常而不是SRegExIndexOutOfBounds

于 2011-03-16T10:09:31.667 回答
5

该错误似乎在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。

uses如果我从子句中删除 RegularExpressionsAPI并pcre从我的TPerlRegEx 组件中添加单位,那么它会正确打印 1 和 2。

RegularExpressionsAPIDelphi XE中的以我的单位为pcre单位,RegularExpressionsCore单位以我的单位为PerlRegEx单位。Embarcadero 确实对两个单位进行了一些更改。他们还从 PCRE 库中编译了自己的 OBJ 文件,这些文件由RegularExpressionsAPI.

我已将此错误报告为QC 92497

我还创建了一个单独的报告QC 92498,以请求TGroupCollection.GetItem在请求不存在的命名组时引发更明智的异常。(此代码在RegularExpressions基于 Vincent Parrett 编写的代码的单元中,而不是我自己。)

于 2011-03-23T03:25:37.770 回答