RegEx callout function and closures Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
william_ahk
Posts: 481
Joined: 03 Dec 2018, 20:02

RegEx callout function and closures

Post by william_ahk » 25 Nov 2022, 02:55

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? :shock:

lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: RegEx callout function and closures  Topic is solved

Post by lexikos » 25 Nov 2022, 22:46

AutoHotkey caches the last 100 regex patterns, so callouts and function objects are inherently unsafe to use in this manner at present.
Source: v2 RegExReplace Callout Bug - AutoHotkey Community
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.

william_ahk
Posts: 481
Joined: 03 Dec 2018, 20:02

Re: RegEx callout function and closures

Post by william_ahk » 26 Nov 2022, 00:53

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! :trollface:

User avatar
thqby
Posts: 396
Joined: 16 Apr 2021, 11:18
Contact:

Re: RegEx callout function and closures

Post by thqby » 27 Nov 2022, 07:17

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

lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: RegEx callout function and closures

Post by lexikos » 27 Nov 2022, 17:22

@thqby :thumbup:

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.

lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: RegEx callout function and closures

Post by lexikos » 09 Dec 2022, 20:23

The fix was implemented by v2.0-rc.2.

I decided to defer any changes to RegExReplace until v2.1.

Post Reply

Return to “Ask for Help (v2)”