我在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”,正如预期的那样。有保留的话我不能用吗?我不这么认为,因为在我的真实例子中,我尝试过完全随机的名字。我无法弄清楚导致这种行为的原因。
答案 0 :(得分:7)
当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
答案 1 :(得分:5)
该错误似乎位于包含PCRE库的RegularExpressionsAPI
单元中,或者在它链接的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并从我的TPerlRegEx component添加pcre
单元,则它会正确打印1和2.
Delphi XE中的RegularExpressionsAPI
基于我的pcre
单元,RegularExpressionsCore
单元基于我的PerlRegEx
单元。 Embarcadero确实对这两个单位做了一些改变。他们还从PCRE库中编译了自己的OBJ文件,这些文件由RegularExpressionsAPI
链接。
我已将此错误报告为QC 92497
我还创建了一个单独的报告QC 92498,以请求TGroupCollection.GetItem
在请求不存在的命名组时引发更明智的异常。 (此代码位于RegularExpressions
单元中,该单元基于Vincent Parrett编写的代码,而非我自己。