Page 1 of 1

[v2] RegExReplace callout with global variable

Posted: 12 Feb 2022, 01:37
by quaritexa

Code: Select all

replace(m, *) {
  global q
  q := %m.1%
}

q := "bug"
w := RegExReplace("#include %A_MyDocuments%\test", "%(A_\w+)%(?Creplace)", q)
;w -> #include bug\test

q := "                                                 "
w := RegExReplace("#include %A_MyDocuments%\test", "%(A_\w+)%(?Creplace)", q)
;w -> #include C:\Users\user\Documents\test
Why?

Re: [v2] RegExReplace callout with global variable

Posted: 12 Feb 2022, 08:46
by neogna2
Is (?Creplace) valid syntax for the NeedleRegEx parameter in RegExReplace()?

Re: [v2] RegExReplace callout with global variable

Posted: 12 Feb 2022, 13:14
by quaritexa
@neogna2
Yes

Re: [v2] RegExReplace callout with global variable

Posted: 13 Feb 2022, 07:11
by neogna2
@quaritexa: yeah sorry I misremembered the Callouts syntax. The issue seems to happen in v1 too. This v2 test shows some variation, don't know what the cause is.

Code: Select all

replace(m, *) {
    global q
    q := %m.1%
}

For Key, A_Val in [A_MyDocuments, A_Now, A_Language]
{
    w := ""
    For Key, Val in ["bug", "bu", "b"]
        Loop 20
        {
            q := StrReplace( Format("{:" A_Index "}", "") , " ", Val) ;return string that repeats Val A_Index times
            w .= A_Index ":  " RegExReplace("#include %A_Val%\test", "%(A_\w+)%(?Creplace)", q) "`n"
        }
    MsgBox w
    ;loop 1   to N   replaces with q (from before the callout)
    ;loop N+1 to end replaces with A_Val (q value set in callout)
    ;number N varies with both q and A_Val
}

Re: [v2] RegExReplace callout with global variable

Posted: 06 Apr 2022, 08:24
by Helgef
The reason there is no noticeable problem on the first call is that %m.1% in q := %m.1% doesn't fit in q's string buffer, so a new buffer is created. But on the second call, there is enough space in the buffer, so its content is just updated. The problem is that regexreplace didn't make a copy of the buffer so it sees the update.
Here is an example where there is enough space in the buffer on the first call,

Code: Select all

replace(m, *) {
  global q
  q := '+++'
}
q := "abc"
w := RegExReplace('123', "2(?Creplace)", q)
msgbox w
You can even change the haystack from the callout. I do not think it is worth the bother to fix this. In particular, it implies that we need to make copies of the inputs which in ~99.99999% of the time would be a waste. I think it should be sufficient to add a note in the documentation, stating that callout functions should avoid changing the input parameters of regexreplace (and regexmatch).

Cheers.

Re: [v2] RegExReplace callout with global variable

Posted: 16 Aug 2022, 07:27
by quaritexa
Another example:

Code: Select all

q := "                                                 "
path := "Ver %A_AhkVersion%, ID %A_ScriptHwnd%"
MsgBox RegExReplace(path, "%(A_\w*?)%(?Creplace)", q)
replace(m, *) {
  global q
  q := %m.1%
  q := StrLen(q)
}
Will show: Ver 2.0-beta.7, ID 5578266

But

Code: Select all

q := "                                                 "
path := "Ver %A_AhkVersion%, ID %A_ScriptHwnd%"
MsgBox RegExReplace(path, "%(A_\w*?)%(?Creplace)", q)
replace(m, *) {
  global q
  q := %m.1%
  q := StrLen(q)
  MsgBox q,,"T.001"
}
Will show: Ver 10, ID 8

Image

Re: [v2] RegExReplace callout with global variable  Topic is solved

Posted: 17 Aug 2022, 20:03
by lexikos
If any of the input parameters to a RegEx function is modified during a callout, the behaviour is undefined.
https://lexikos.github.io/v2/docs/misc/RegExCallout.htm#callout-functions