使用自定义处理替换另一个字符串中出现的字符串

Replace occurrences of a string in another string with custom processing

假设我有一个字符串

myString := 'aa12bb23cc34dd'

我想用它的值乘以 2 来替换每个出现的数字(我的实际应用会更复杂,这是为了示例):

myUpdatedString := 'aa24bb46cc68dd'

我知道 Regexpr 中的 ReplaceRegExpr 可以像 Sed 一样使用,但它不会将函数作为参数应用于匹配的元素。

目前,我正在做这样的事情(可能有点 ugly/invalid 但重要的是做事的方式):

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() 构建的方法非常相似。