问题描述
myString := 'aa12bb23cc34dd'
我想用它的值乘以 2 替换每个出现的数字(我的实际应用会更复杂,这是示例):
myUpdatedString := 'aa24bb46cc68dd'
我知道 Regexpr 中的 ReplaceRegExpr,它可以像 Sed 一样使用,但它不会将函数作为参数应用于匹配的元素。
目前,我正在做这样的事情(可能有点丑陋/无效,但重要的是这样做的方式):
program Project1;
uses
SysUtils,RegExpr;
// The function I would like to call on my matched element
function foo(const x: integer): integer;
begin
result = x * 2;
end;
function bar(const base,s: string): string;
var
pos: integer;
s2: string;
begin
// Application of foo
s2 := foo(StrToInt(s)).ToString;
// Substitution of the matched string
result = StringReplace(base,s,s2);
end;
var
re: TRegExpr;
myString,myUpdatedString: string;
begin
myString := 'aa12bb23cc34dd';
re := TRegExpr.Create('[0-9]+');
if re.Exec(myString) then
begin
// For each matched elements
myUpdatedString := bar(myString,re.Match[1]);
while re.ExecNext do
begin
myUpdatedString := bar(myString,re.Match[1]);
end;
end;
re.Free;
end.
难道没有更轻松或更优雅的方法吗?
像 ReplaceRegExpr 这样将函数作为参数应用于匹配元素的函数会是最好的,但我找不到任何。
感谢您的帮助!
编辑:在我的实际应用中,我不需要替换数字,而是替换 HTML 流的各种标签中的属性值。我想修改来自各种标签的各种元素,这些值需要大量计算才能知道用什么替换它们。我认为这是一个简单问题的大量信息。
解决方法
TRegExpr
已经带有 .Replace()
和 .ReplaceEx()
,您可以将 TRegExprWReplaceFunction
形式的函数传递给它们,该函数在每次匹配出现时都会被调用。您决定结果,然后将其用作匹配的替换。这样你就可以自定义它了。示例:
type
TDum= class // Must be a function of object,hence a helper class
class function MyReplace( re: TRegExpr ): String;
end;
class function TDum.MyReplace( re: TRegExpr ): String;
begin
// Example: convert matching text to number,double it,convert back to text
result:= IntToStr( StrToInt( re.Match[1] )* 2 );
end;
...
myUpdatedString:= re.Replace( 'aa12bb23cc34dd',TDum.MyReplace );
// Should have become 'aa24bb46cc68dd'
如果您查看 TRegExp 的源代码,您会发现这些方法与您已经使用 .Exec()
和 .ExecNext()
构建的方法非常相似。