Hi all,
Question:
Is it possible to modify the value of a backreference in RegExReplace before feeding it back as part of the replacement text?
I can of course do it with a workaround using RegExMatch, working with its RegExMatchInfo object to manipulate the whole text each time a match is found, and searching multiple times with increasing starting positions until no more matches are found. But, as I wrote, I consider this more of a workaround.
I also looked into the RegEx Callouts option, but any solution with that seems to be even more workaroundish than with RegExMatch, unless I did not fully understand its capabilities?
I just thought, maybe there is a quick and easy way with RegExReplace, that I either overlooked or that is not documented officially?
Does anyone of you readers know of such a way?
MTIA and regards, a.
RegExReplace: Can I modify the value of a backreference?
RegExReplace: Can I modify the value of a backreference?
Last edited by BoBo on 24 Jan 2023, 11:17, edited 1 time in total.
Reason: Topic moved from 'Ask For Help' to 'AutoHotkey v2 Scripts and Functions' on request by the OP.
Reason: Topic moved from 'Ask For Help' to 'AutoHotkey v2 Scripts and Functions' on request by the OP.
Re: RegExReplace: Can I modify the value of a backreference?
I believe that the answer is "no". Although you can use the reference in a larger string, you cannot modify the reference itself.
Last edited by mikeyww on 23 Jan 2023, 10:32, edited 1 time in total.
Re: RegExReplace: Can I modify the value of a backreference?
Ok, I was afraid of that but thanks for the confirmation.
Re: RegExReplace: Can I modify the value of a backreference?
I believe that you also cannot wrap the backref in a function.
Code: Select all
#Requires AutoHotkey v2.0
str := "abcd"
regex := ".+(c).*"
MsgBox RegExReplace(str, regex, "$1")
MsgBox RegExReplace(str, regex, SubStr("$1", 1, 1))
Re: RegExReplace: Can I modify the value of a backreference?
Yes, thank you for brainstorming.
This was the first idea that came to my mind as well, but I never tried it because it would not make any sense in connection with how RegExReplace is described in the help. So, I agreeingly also assume that it cannot be done, just as you wrote.
This was the first idea that came to my mind as well, but I never tried it because it would not make any sense in connection with how RegExReplace is described in the help. So, I agreeingly also assume that it cannot be done, just as you wrote.
Re: RegExReplace: Can I modify the value of a backreference?
When you have the result, you can use it in any way, of course.
I think of it as a specific placeholder that is only used in that parameter of RegExReplace. It cannot be used as an expression.
From the documentation:
Code: Select all
#Requires AutoHotkey v2.0
str := "abcd"
regex := ".+(c).*"
MsgBox RegExReplace(str, regex, "$1") ; OK
MsgBox RegExReplace(str, regex, SubStr("$1", 1, 1)) ; No
MsgBox SubStr(RegExReplace(str, regex, "$1"), 1, 1) ; OK
Code: Select all
#Requires AutoHotkey v2.0
str := "ab1d"
regex := ".+(1).*"
MsgBox RegExReplace(str, regex, "$1")
MsgBox RegExReplace(str, regex, 3 + "$1")
viewtopic.php?f=86&t=113023Replacement: The string to be substituted for each match, which is plain text (not a regular expression).
Re: RegExReplace: Can I modify the value of a backreference?
Ok, I now threw toghether some lines of code to try to make my own _RegExReplace_Enhanced function that would allow what I want.
Whoever has the time and nerves needed, please have a look and give advice as to how I can improve it, so that it would be more professional. Many many thanks in advance (MMTIA)!
How it works:
In general, it works like RegExReplace but instead of the Replacement parameter it expects the name of a user written function (in the form of a string). That function must receive a RegExMatchInfo object as parameter and can, thus, manipulate also all values of backreferences to matched subpatterns. The function must return a string that is used as replacement for each found match.
An application example:
The message box should display
Whoever has the time and nerves needed, please have a look and give advice as to how I can improve it, so that it would be more professional. Many many thanks in advance (MMTIA)!
How it works:
In general, it works like RegExReplace but instead of the Replacement parameter it expects the name of a user written function (in the form of a string). That function must receive a RegExMatchInfo object as parameter and can, thus, manipulate also all values of backreferences to matched subpatterns. The function must return a string that is used as replacement for each found match.
An application example:
Code: Select all
vOrgString := 'abc="95.123"def="12.456789"ghi'
vNewString := _RegExReplace_Enhanced(vOrgString, '="(\d+\.\d+)"', "_FixNumberInMatch", &vCount)
MsgBox vNewString "`n`nCount of matches: " vCount
_FixNumberInMatch(vMatchInfo_ob) {
return '="' Ceil(vMatchInfo_ob[1]) '"'
}
Here is the actual _RegExReplace_Enhanced function:abc="96"def="13"ghi
Count of matches: 2
Code: Select all
_RegExReplace_Enhanced(pHaystack, pNeedleRegEx, pReplacementFunction?, &pOutputVarCount := 0, pLimit := -1, pStartingPos := 1) {
if IsSet(pReplacementFunction) and not HasMethod(%pReplacementFunction%, , 1) {
; return ""
return pHaystack
}
vFoundMatches_Count := 0
vStartingPos := pStartingPos
if vStartingPos <= 0 {
vStartingPos := StrLen(pHaystack) + 1 - (-1 * vStartingPos) ; compare RegExMatch
}
vWorkingString := SubStr(pHaystack, 1, vStartingPos - 1)
while (pLimit = -1 or vFoundMatches_Count < pLimit) and (vFoundPos := RegExMatch(pHaystack, pNeedleRegEx, &vMatchInfo_ob, vStartingPos)) > 0 {
vFoundMatches_Count++
vSubStringFromLastStartingPosToFoundMatch := SubStr(pHaystack, vStartingPos, vFoundPos - vStartingPos)
vStartingPos := vFoundPos + StrLen(vMatchInfo_ob[0])
vWorkingString .= vSubStringFromLastStartingPosToFoundMatch
; vReplacementString := ""
vReplacementString := vMatchInfo_ob[0]
if IsSet(pReplacementFunction) {
try vReplacementString := %pReplacementFunction%(vMatchInfo_ob)
catch {
;
}
}
vWorkingString .= vReplacementString
}
pOutputVarCount := vFoundMatches_Count
return vWorkingString . SubStr(pHaystack, vStartingPos)
}
Last edited by autocart on 25 Jan 2023, 08:21, edited 1 time in total.
Re: RegExReplace: Can I modify the value of a backreference? Topic is solved
UPDATE:
I just improved the "error handling" a little bit.
I just improved the "error handling" a little bit.
Code: Select all
_RegExReplace_Enhanced(pHaystack, pNeedleRegEx, pReplacementFunction?, &pOutputVarCount := 0, pLimit := -1, pStartingPos := 1) {
if IsSet(pReplacementFunction) and not HasMethod(%pReplacementFunction%, , 1) {
MsgBox "Problem 1: The passed replacement function can not be executed. Haystack is not changed."
; return ""
return pHaystack
}
vFoundMatches_Count := 0
vStartingPos := pStartingPos
if vStartingPos <= 0 {
vStartingPos := StrLen(pHaystack) + 1 - (-1 * vStartingPos) ; compare RegExMatch
}
vWorkingString := SubStr(pHaystack, 1, vStartingPos - 1)
while (pLimit = -1 or vFoundMatches_Count < pLimit) and (vFoundPos := RegExMatch(pHaystack, pNeedleRegEx, &vMatchInfo_ob, vStartingPos)) > 0 {
vFoundMatches_Count++
vSubStringFromLastStartingPosToFoundMatch := SubStr(pHaystack, vStartingPos, vFoundPos - vStartingPos)
vStartingPos := vFoundPos + StrLen(vMatchInfo_ob[0])
vWorkingString .= vSubStringFromLastStartingPosToFoundMatch
; vReplacementString := ""
vReplacementString := vMatchInfo_ob[0] ; just trying to be extra safe
if IsSet(pReplacementFunction) {
try vReplacementString := %pReplacementFunction%(vMatchInfo_ob)
catch {
MsgBox "Problem 2: There was a problem while trying to execute the replacement function. Haystack is not changed."
return pHaystack
}
} else {
MsgBox "Problem 3: The passed parameter for the replacement function seems to not be set. Haystack is not changed."
return pHaystack
}
vWorkingString .= vReplacementString
}
pOutputVarCount := vFoundMatches_Count
return vWorkingString . SubStr(pHaystack, vStartingPos)
}
Last edited by autocart on 25 Jan 2023, 08:21, edited 1 time in total.
Re: RegExReplace: Can I modify the value of a backreference?
Just as a side note for the record:
The function also works well for generally executing some sub-function based on each found match, e.g. for data extraction (without having to necessarily change haystack).
Probably, there could be faster code, but for me this seems quite a comfortable solution so far.
The function also works well for generally executing some sub-function based on each found match, e.g. for data extraction (without having to necessarily change haystack).
Probably, there could be faster code, but for me this seems quite a comfortable solution so far.
Re: RegExReplace: Can I modify the value of a backreference?
UPDATE:
I had a bug in the code in line 10, respectively, 11. Fixed it in both versions up above.
New, correct line:
vStartingPos := StrLen(pHaystack) + 1 - (-1 * vStartingPos) ; compare RegExMatch
Old, wrong line:
vWorkingString := StrLen(pHaystack) + 1 - (-1 * vStartingPos) ; compare RegExMatch
I had a bug in the code in line 10, respectively, 11. Fixed it in both versions up above.
New, correct line:
vStartingPos := StrLen(pHaystack) + 1 - (-1 * vStartingPos) ; compare RegExMatch
Old, wrong line:
Return to “Scripts and Functions (v2)”
Who is online
Users browsing this forum: No registered users and 16 guests