Page 1 of 1
RegEx callout function and closures
Posted: 25 Nov 2022, 02:55
by william_ahk
Code: Select all
DecodeEscapeChar(str) {
static esc := {n: "`n", r: "`r", b: "`b", t: "`t", v: "`v", a: "`a", f: "`f"}
static output
output := ""
loop {
count := 0
str := RegExReplace(str, "(.*?)(\\)(.)(?CCallout)", , &c)
count += c
} until !count
output .= str
return output
Callout(m, *) {
output .= m[1] . (m[3] = "\" ? m[3] : esc.HasOwnProp(m[3]) ? esc.%m[3]% : "")
}
}
msgbox DecodeEscapeChar("1\n2\n3")
msgbox DecodeEscapeChar("1\n2\n3")
The code above works, but it's the result of trial and error and I'm not understanding it. If the output variable is not declared static, the second call to this function will throw
Invalid memory read/write. Why? Can someone explain?
Re: RegEx callout function and closures Topic is solved
Posted: 25 Nov 2022, 22:46
by lexikos
Making
output static implicitly also makes
Callout static, because it then doesn't capture any variables. I would recommend making it explicitly static (
static Callout(m, *)).
Omitting the function name and using the
pcre_callout variable is safer (but slower), because the variable is resolved each time a callout is made, and not cached in the pattern. However, the variable has to be in scope when the pattern is evaluated.
As an aside, I often want to do something like what you are doing, and I tentatively plan to support it by allowing RegExReplace to accept a function instead of a string for the replacement.
Re: RegEx callout function and closures
Posted: 26 Nov 2022, 00:53
by william_ahk
lexikos wrote: ↑25 Nov 2022, 22:46
Omitting the function name and using the
pcre_callout variable is safer (but slower), because the variable is resolved each time a callout is made, and not cached in the pattern. However, the variable has to be in scope when the pattern is evaluated.
I'll just use
pcre_callout then, I did a test and the speed difference is negligible.
Code: Select all
DecodeEscapeChar(str) {
static esc := {n: "`n", r: "`r", b: "`b", t: "`t", v: "`v", a: "`a", f: "`f"}
output := ""
str := RegExReplace(str, "(.*?)(\\)(.)(?C)")
output .= str
return output
pcre_callout(m, *) {
output .= m[1] . (m[3] = "\" ? m[3] : esc.HasOwnProp(m[3]) ? esc.%m[3]% : "")
}
}
msgbox DecodeEscapeChar("1\n2\n3")
msgbox DecodeEscapeChar("1\n2\n3")
lexikos wrote: ↑25 Nov 2022, 22:46
As an aside, I often want to do something like what you are doing, and I tentatively plan to support it by allowing RegExReplace to accept a function instead of a string for the replacement.
That would be awesome!
Re: RegEx callout function and closures
Posted: 27 Nov 2022, 07:17
by thqby
lexikos wrote: ↑25 Nov 2022, 22:46
As an aside, I often want to do something like what you are doing, and I tentatively plan to support it by allowing RegExReplace to accept a function instead of a string for the replacement.
I've implemented this.
PR #307
Re: RegEx callout function and closures
Posted: 27 Nov 2022, 17:22
by lexikos
@thqby
I planned to not introduce any new features in v2.0, but I'll consider whether to make an exception after reviewing the PR and thorough testing. It would be helpful if someone could write test cases that cover old and new functionality.
On the other hand, v2.1-alpha won't be far away.
As for the main topic, I've changed callouts to be resolved at callout time, but haven't pushed it to GitHub yet.
Re: RegEx callout function and closures
Posted: 09 Dec 2022, 20:23
by lexikos
The fix was implemented by v2.0-rc.2.
I decided to defer any changes to RegExReplace until v2.1.