Yuni Tsukiyama
Yuni Tsukiyama

Reputation: 121

Replace occurrences of a string in another string with custom processing

Let's say I have a string

myString := 'aa12bb23cc34dd'

I'd like to replace every occurrences of a number by its value times 2 (my practical application would be something more complicated, this is for the example):

myUpdatedString := 'aa24bb46cc68dd'

I know ReplaceRegExpr from Regexpr which can be used just like Sed but it does not take functions as parameters to be applied to the matched elements.

For the moment, I'm doing something like this (might be a bit ugly/invalid but what matters is the way of doing):

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.

Isn't there a lighter or more elegant way of doing it?

A function like ReplaceRegExpr taking functions as parameters to apply to matched elements would be the best but I couldn't find any.

Thank you for your help!

Edit: In my practical application, I don't need to replace numbers but values of attributes in various tags of an HTML flow. I want to modify various elements from various tags and these values needs a lot of computation before I know what to replace them with. I thought this was to much information for a simple problem.

Upvotes: 2

Views: 285

Answers (1)

AmigoJack
AmigoJack

Reputation: 6099

TRegExpr already comes with .Replace() and .ReplaceEx() to which you hand over a function in the form of TRegExprWReplaceFunction that gets called for each matching occurance. In that you decide the result, which is then used as replacement for the match. That way you can already customize it. Example:

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'

If you look at the source of TRegExp you'll see that those methods are very similar to what you constructed with .Exec() and .ExecNext() already.

Upvotes: 4

Related Questions