Is there a RegExMatch option to search right to left?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Heezea
Posts: 59
Joined: 30 Sep 2013, 21:33

Is there a RegExMatch option to search right to left?

11 Sep 2014, 18:32

Hey, is it possible to search right to left using RegExMatch? I know it can be done with InStr() by setting starting position to 0, but was wondering about RegEx.

Thanks.
kon
Posts: 1756
Joined: 29 Sep 2013, 17:11

Re: Is there a RegExMatch option to search right to left?

11 Sep 2014, 20:10

You can use $ to anchor the regular expression to the end of the text (or to the end of a line if it is used in conjunction with the m option).

Code: Select all

Test := "abc1abc2abc3"
RegExMatch(Test, "abc\d$", m)
MsgBox, % m
If you need a more specific example post a sample haystack and needle desired match.
User avatar
RobertL
Posts: 546
Joined: 18 Jan 2014, 01:14
Location: China

Re: Is there a RegExMatch option to search right to left?

11 Sep 2014, 21:21

Not correct, see posts below.
Like this? Pattern "a.*?$" search the first "a" from left to right.
Key: use $ to fix left boundary, and ? makes quantifiers *+?{} ungreedy.
Last edited by RobertL on 12 Sep 2014, 02:07, edited 1 time in total.
我为人人,人人为己?
lexikos
Posts: 9560
Joined: 30 Sep 2013, 04:07
Contact:

Re: Is there a RegExMatch option to search right to left?

12 Sep 2014, 01:46

PCRE (and therefore RegExMatch and RegExReplace) does not support searching right-to-left.

kon: Anchoring to the end will let you find a substring at the end of the haystack. It will not let you search right-to-left.

RobertL: It finds the first "a" from left to right, as you say. That's exactly the opposite of what the OP is asking for.

Making * ungreedy does not help. It will still begin the match at the first 'a' (left to right) it sees and will not try alternative 'a's if the first one matches.

Code: Select all

MsgBox % RegExMatch("b a b a b", "a")		; 3
MsgBox % RegExMatch("b a b a b", "a.*?$")	; 3
MsgBox % RegExMatch("b a b a b", "a.*$")	; 3
For finding the last match, you can usually use greedy .*:

Code: Select all

MsgBox % RegExMatch("b a b a b", ".*\Ka")
\K excludes the part matched by .* from the final result.

A negative look-ahead assertion will usually also work:

Code: Select all

MsgBox % RegExMatch("b a b a b", "(a)(?!.*(?1))")
(?1) is used to avoid repeating the pattern. It refers to the (a) part of the pattern.
User avatar
RobertL
Posts: 546
Joined: 18 Jan 2014, 01:14
Location: China

Re: Is there a RegExMatch option to search right to left?

12 Sep 2014, 02:01

Aha, I find could use \K almost the same time~
Also, thanks for negative look-ahead with back references method.
我为人人,人人为己?
ahcahc
Posts: 110
Joined: 25 Jul 2014, 23:55

Re: Is there a RegExMatch option to search right to left?

12 Sep 2014, 03:52

Code: Select all

h:="a b c d fffffffffaffffffffafffffd"
n=a
loop, % strlen(h)
if pos := RegExMatch(A_index=1?h:SubStr(h,1,strlen(h)-StrLen(n)*A_Index),n,m,strlen(h)-StrLen(n)*A_Index)
  MsgBox % " found ``" m "`` at position " pos
User avatar
RobertL
Posts: 546
Joined: 18 Jan 2014, 01:14
Location: China

Re: Is there a RegExMatch option to search right to left?

12 Sep 2014, 04:35

Code: Select all

RegExMatch("b a b a b", "O).*(a)",o)
MsgBox % o.Pos[1]	;7
我为人人,人人为己?
User avatar
trismarck
Posts: 506
Joined: 30 Sep 2013, 01:48
Location: Poland

Re: Is there a RegExMatch option to search right to left?

12 Sep 2014, 05:21

I remember one idea for this was to turnaround both the haystack and needles accordingly.

Code: Select all

Test := "abc1abc2abc3"
Loop, Parse, Test
	out := A_LoopField out
MsgBox % out
RegExMatch(out, "\dcba", m)
MsgBox, % m
User avatar
RobertL
Posts: 546
Joined: 18 Jan 2014, 01:14
Location: China

Re: Is there a RegExMatch option to search right to left?

12 Sep 2014, 05:48

Aha, turnaround both the haystack and needles accordingly would be confused and disoriented, especially writing pattern.
Wait, could it deal with "b a b a b", to find the first "b" from left? Remember to turnaround the position of result.. :crazy:

Code: Select all

haystack:="b a b a b"
MsgBox % StrLen(haystack) - RegExMatch(haystack, ".*?a") -1	;7

;Use "Once-only subpatterns" (in some case, I'm not sure):
MsgBox % StrLen(haystack) - RegExMatch(haystack, "(?>.*a)")	;7
Last edited by RobertL on 16 Sep 2014, 08:16, edited 1 time in total.
我为人人,人人为己?
ahcahc
Posts: 110
Joined: 25 Jul 2014, 23:55

Re: Is there a RegExMatch option to search right to left?

12 Sep 2014, 06:20

This should work.

Code: Select all

h:="a65 b c d ff1ff3fffabcffaffff12ffffafabcabcb12cd"
n:="\d\d"
;h:="b a b a b"
;n:="b"
loop
if pos := RegExMatch(a_Index=1?h:SubStr(h,1,pos?pos:strlen(h)),n,m,strlen(h)-A_Index)
{
if (strlen(h)-A_Index)<0
        break
if (pos_old!=pos)
    {
    pos_old:=pos
    MsgBox % "Found ``" m "`` at position " pos "`nLenght: " strlen(h)
    }
}
lexikos
Posts: 9560
Joined: 30 Sep 2013, 04:07
Contact:

Re: Is there a RegExMatch option to search right to left?

12 Sep 2014, 21:30

You could match everything and then pull out the result you want. Here are my takes:

Code: Select all

h:="a65 b c d ff1ff3fffabcffaffff12ffffafabcabcb12cd"
n:="\d\d"

s := ""
for i,m in RegExMatchAll(h, n)
    s .= i "=" m.0 "`n"
MsgBox % s

RegExMatchAll(str, pat, pos := 1)
{
    static matches
    if IsObject(str) ; Callout mode
    {
        matches.Insert(str)
        return
    }
    RegExMatch(pat, "sO)(^[^\(]*\))?(.*)", pat)
    opt := pat.1 != "" ? pat.1 : ")"
    pat := "O" opt "(?:" pat.2 ")(?C" A_ThisFunc ")"
    matches := [],  RegExReplace(str, pat, "",,, pos)
    return matches
}
...or the in-line version (but unlike the one above, it doesn't give you the positions):

Code: Select all

h:="a65 b c d ff1ff3fffabcffaffff12ffffafabcabcb12cd"
n:="\d\d"

s := ""
for i,m in StrSplit(Trim(RegExReplace(h, "s).*?(" n "|$)", (d:=Chr(31)) "$1"), d), d)
    s .= i "=" m "`n"
MsgBox % s
For reverse order, you would just iterate from x.MaxIndex() to 1 or retrieve x[x.MaxIndex()-n], where x is the array of results.

Edit: Fixed .+? bug
ahcahc
Posts: 110
Joined: 25 Jul 2014, 23:55

Re: Is there a RegExMatch option to search right to left?

12 Sep 2014, 23:16

With starting position.

Code: Select all

h:="a65 b c d ff1ff3fffabcffaffff12ffffafabcabcb12cd664429123443" 
;n:="\w\w"
;n:="[a-z]\d"
;n:="65"

n:="\d\d\d\d"
pos := RevExMatch(h,n,m,"a",allm,59)
;pos := RevExMatch(h,n,m,"a",allm)
MsgBox % "last matched position: " pos "`nlast matched: " m "`nall matches: " allm "`nhaystack length: " strlen(h)
ExitApp

RevExMatch(h,n, ByRef ma:="", r:="1", ByRef f="",p:="",d:=",") {  ;RevegxMatch() returns the position of the last match starting from the end of the haystack, h=haystack, n=needle, r=2 returns the 2nd match (m) (r=a=all last match), f= store all the matches delimited by d="," p=start position
if (r="a" or r="all")
    r:=strlen(h)
else if r is space
   r=1
else if r is not digit
   r=1
if p is space
    p:=StrLen(h)
else if p is not digit
    p:=StrLen(h)
else if (p>strlen(h))
   p:=StrLen(h)-p
tmp:=0, h2:=h, h:=SubStr(h,1,p)
loop
    {
    if ((strlen(h2)-A_Index )<0)
        return lp
    if pos := RegExMatch(h,n,m,p)
        {
        h:=SubStr(h,1,pos-1), p-=StrLen(m), tmp++, f .= tmp=1?m:d m, lp:=pos, ma:=m
         If (r=tmp)
            return lp
        }
    else
        p--
    }
}
User avatar
RobertL
Posts: 546
Joined: 18 Jan 2014, 01:14
Location: China

Re: Is there a RegExMatch option to search right to left?

12 Sep 2014, 23:25

Wow, what a nice design RegExMatchAll and the in-line version is, from lexikos.
A little bug in the in-line version, "s).+?(" n "|$)" should be "s).*?(" n "|$)", otherwise would miss "12" in "12a34".


Collection and summaries with this topic in Chinese: 正则-匹配模式的所有实例, 正则反向查找.
我为人人,人人为己?
gmoises
Posts: 74
Joined: 18 Nov 2017, 16:43

Re: Is there a RegExMatch option to search right to left?

18 Nov 2017, 17:02

A function can do it, no need for RegEx

Code: Select all

RInStr(Haystack, Needle, CaseSensitive = false, StartingPos = 1, Occurrence = 1) {
	Loop, Parse, Haystack
		nHay := A_LoopField . nHay
	Loop, Parse, Needle
		nNdl := A_LoopField . nNdl
	Pos := InStr(nHay, nNdl, CaseSensitive, StartingPos, Occurrence)
	If (Pos> 0)
		Return 2 + StrLen(Haystack) - Pos - StrLen(Needle)
	Else
		Return 0
}

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: No registered users and 147 guests