使用Delphi的TRegex获取与哪个捕获组匹配的结果

我写了一个正则表达式,其工作是将所有匹配返回给它的三个备选捕获组。 我的目标是了解每场比赛制作哪个擒拿组。 PCRE似乎能够提供这些信息。 但是我还没有能够强迫Delphi XE8中的TRegEx类为匹配产生有意义的捕获组信息。 我不能声称是在正则表达式类的头上, TRegEx对我来说是新的,所以谁知道我在做什么错误。

正则表达式(regex101.com工作板)是:

(?'word'b[a-zA-Z]{3,}b)|(?'id'bd{1,3}b)|(?'course'b[BL]d{3}b)

本测试文字:

externship L763 clinic 207 B706 b512

在测试环境中给出五个匹配。 但是,走在一个简单的测试程序TGroupCollection每个TMatchTMatchCollection显示有关组奇怪的结果:所有的比赛有一个以上的组(2,3或4),每组的Success如此,而且经常匹配的文本在几个复制组或是空的。 所以这个数据结构(下面)不是我所期望的:

Using TRegEx
Regex: (?'word'b[a-zA-Z]{3,}b)|(?'id'bd{1,3}b)|(?'course'b[BL]d{3}b)
Text: externship L763 clinic 207 B706 b512

5 matches
 'externship' with 2 groups:
    length 10 at 1 value 'externship' (Sucess? True)
    length 10 at 1 value 'externship' (Sucess? True)
 'L763' with 4 groups:
    length 4 at 12 value 'L763' (Sucess? True)
    length 0 at 1 value '' (Sucess? True)
    length 0 at 1 value '' (Sucess? True)
    length 4 at 12 value 'L763' (Sucess? True)
 'clinic' with 2 groups:
    length 6 at 17 value 'clinic' (Sucess? True)
    length 6 at 17 value 'clinic' (Sucess? True)
 '207' with 3 groups:
    length 3 at 24 value '207' (Sucess? True)
    length 0 at 1 value '' (Sucess? True)
    length 3 at 24 value '207' (Sucess? True)
 'B706' with 4 groups:
    length 4 at 28 value 'B706' (Sucess? True)
    length 0 at 1 value '' (Sucess? True)
    length 0 at 1 value '' (Sucess? True)
    length 4 at 28 value 'B706' (Sucess? True)

我的简单测试跑者是这样的:

program regex_tester;
{$APPTYPE CONSOLE}
{$R *.res}
uses
  System.SysUtils,
  System.RegularExpressions,
  System.RegularExpressionsCore;

var
  Matched     : Boolean;
  J           : integer;
  Group       : TGroup;
  Match       : TMatch;
  Matches     : TMatchCollection;
  RegexText,
  TestText    : String;
  RX          : TRegEx;
  RXPerl      : TPerlRegEx;

begin
  try
    RegexText:='(?''word''b[a-zA-Z]{3,}b)|(?''id''bd{1,3}b)|(?''course''b[BL]d{3}b)';
    TestText:='externship L763 clinic 207 B706 b512';

    RX:=TRegex.Create(RegexText);

    Matches:=RX.Matches(TestText);

    Writeln(Format(#10#13#10#13'Using TRegEx'#10#13'Regex: %s'#10#13'Text: %s'#10#13,[RegexText, TestText]));

    Writeln(Format('%d matches', [Matches.Count]));
    for Match in Matches do
    begin
      Writeln(Format(' ''%s'' with %d groups:', [Match.Value,Match.Groups.Count]));

      for Group in Match.Groups do
        Writeln(Format(#9'length %d at %d value ''%s'' (Sucess? %s)', [Group.Length,Group.Index,Group.Value,BoolToStr(Group.Success, True)]));
    end;

    RXPerl:=TPerlRegEx.Create;
    RXPerl.Subject:=TestText;
    RXPerl.RegEx:=RegexText;

    Writeln(Format(#10#13#10#13'Using TPerlRegEx'#10#13'Regex: %s'#10#13'Text: %s'#10#13,[RXPerl.Regex, RXPerl.Subject]));

    Matched:=RXPerl.Match;
    if Matched then
    repeat
      begin
        Writeln(Format(' ''%s'' with %d groups:', [RXPerl.MatchedText,RXPerl.GroupCount]));
        for J:=1 to RXPerl.GroupCount do
          Writeln(Format(#9'length %d at %d, value ''%s''',[RXPerl.GroupLengths[J],RXPerl.GroupOffsets[J],RXPerl.Groups[J]]));

        Matched:=RXPerl.MatchAgain;
      end;
    until Matched=false;

  except
      on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
  end;
end.

我肯定会喜欢朝着正确的方向轻推。 如果TRegEx被破坏,我当然可以使用替代方案 - 或者我可以放弃解决方案的优雅感,而不是使用三个更简单的测试来查找我需要的信息位。

增加了信息和解释

正如@andrei-galatyn所指出的, TRegEx使用TPerlRegEx进行工作。 所以我在我的测试程序中增加了一个部分(输出如下),我也在那里进行实验。 使用TRegEx并不方便,但它的结果是它应该是什么 - 并且没有TRegEx破坏的TGroup数据结构的问题。 无论我使用哪一个班级,最后一组的指数(TRegEx减1)就是我想要的获取组。

一路上我都被提醒说,Pascal数组通常基于1而不是0。

Using TPerlRegEx
Regex: (?'word'b[a-zA-Z]{3,}b)|(?'id'bd{1,3}b)|(?'course'b[BL]d{3}b)
Text: externship L763 clinic 207 B706 b512

 'externship' with 1 groups:
    length 10 at 1, value 'externship'
 'L763' with 3 groups:
    length 0 at 1, value ''
    length 0 at 1, value ''
    length 4 at 12, value 'L763'
 'clinic' with 1 groups:
    length 6 at 17, value 'clinic'
 '207' with 2 groups:
    length 0 at 1, value ''
    length 3 at 24, value '207'
 'B706' with 3 groups:
    length 0 at 1, value ''
    length 0 at 1, value ''
    length 4 at 28, value 'B706'

内部Delphi使用类TPerlRegEx,它对GroupCount属性具有这样的描述:

存储在Groups数组中的匹配组的数量。 这个数字是您的正则表达式中实际参与最后一场比赛的最高编号的捕获组的编号。 它可能少于正则表达式中捕获组的数量。

例如,当正则表达式“(a)|(b)”匹配“a”时,GroupCount将为1.当相同的正则表达式匹配“b”时,GroupCount将为2。

TRegEx类总是添加一个组(对于我猜测的整个表达式)。 在你的情况下,它应该足以检查这样的每场比赛:

case Match.Groups.Count-1 of
  1: ; // "word" found
  2: ; // "id" found
  3: ; // "course" found
end;

它没有回答为什么组充满了奇怪的数据,事实上它似乎足以回答你的问题。 :)

链接地址: http://www.djcxy.com/p/74817.html

上一篇: Get which capture group matched a result using Delphi's TRegex

下一篇: Using a regex capture directly in expression in C++