Reputation: 121
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
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