Pha*_*aoh 10 regex delphi backreference delphi-xe4
我有一个问题TRegEx.replace:
var
Value, Pattern, Replace: string;
begin
Value := 'my_replace_string(4)=my_replace_string(5)';
Pattern := 'my_replace_string\((\d+)\)';
Replace := 'new_value(\1)';
Value := TRegEx.Replace(Value, Pattern, Replace);
ShowMessage(Value);
end;
Run Code Online (Sandbox Code Playgroud)
new_value(4)=new_value(5)我的代码(用Delphi XE4编译)给出了预期的结果new_value(4)=new_value()1)
使用Notepad ++,我得到了预期的结果.
使用命名组可以清楚地看出1是字面意义上的后向引用:
Pattern := 'my_replace_string\((?<name>\d+)\)';
Replace := 'new_value(${name})';
// Result: 'new_value(4)=new_value(){name})'
Run Code Online (Sandbox Code Playgroud)
替换总是那么简单(可能是零次或多次my_replace_string),所以我可以轻松创建自定义搜索和替换功能,但我想知道这里发生了什么.
这是我的错,还是一个错误?
Jan*_*rts 13
我可以重现Delphi XE4中的错误.我在Delphi XE5中得到了正确的行为.
这个bug就在TPerlRegEx.ComputeReplacement.我使用Delphi XE3为Embarcadero贡献的代码UTF8String.随着德尔福XE4 Embarcadero UTF8String从该RegularExpressionsCore单元中淘汰并取而代之TBytes.进行此更改的开发人员似乎错过了Delphi中字符串和动态数组之间的重要区别.字符串使用写时复制机制,而动态数组则不使用.
因此,在我的原始代码中,TPerlRegEx.ComputeReplacement可以执行S := FReplacement然后修改临时变量S以替换反向引用而不影响FReplacement字段,因为两者都是字符串.在修改后的代码,S := FReplacement使得S指向相同的阵列FReplacement,并且当反向引用在S被取代时,FReplacement也被修改.因此,第一次更换是正确的,而后续更换是错误的,因为FReplacement已经瘫痪.
在Delphi XE5中,通过替换S := FReplacement它来修复此问题以制作适当的临时副本:
SetLength(S, Length(FReplacement));
Move(FReplacement[0], S[0], Length(FReplacement));
Run Code Online (Sandbox Code Playgroud)
当Delphi 2009发布时,Embarcadero发表了很多关于不应该使用字符串类型来表示字节序列的讨论.现在看来他们正在犯下使用TBytes来表示字符串的相反错误.
我之前向Embarcadero推荐的整个混乱的解决方案是切换到使用UTF16LE的新pcre16函数,就像Delphi字符串一样.当Delphi XE发布时,这些功能不存在,但它们现在已经存在,应该使用它们.