3

In AHK i'm trying to populate an array of matches in the style of match[i]. Here is what I have so far:

string = "red"
RegExMatch(string, "O)([a-z])", Match)
MsgBox % Match[1] . Match[2] . Match[3]

However, it merely returns r instead of red.

Any help is greatly appreciated.

TiredofGoogling
  • 197
  • 1
  • 2
  • 9

2 Answers2

3

There is no such thing as "Matches" in RegExMatch(). The documentation says

returns the position of the leftmost occurrence of NeedleRegEx in the string Haystack

and "Mode 3 (match object)" (which is what you used) says

a match object [...] retrieve[s] the position, length and value of the overall match and of each captured subpattern, if present.

Meaning, the subpattern(s) apply only to the leftmost match. Your expression contains only one subpattern: ([a-z]).

To catch multiple matches (of the same expression) within the same string, you'll have to build a loop around it and shift the StartingPosition parameter accordingly.

phil294
  • 10,038
  • 8
  • 65
  • 98
0

Here is my implementation (tested, but no guarantee for no bug)

It loops & RegExMatch & shift to next position +> to find all match objects.

; you need to use `O)` in your regex to use match object
; https://www.autohotkey.com/boards/viewtopic.php?t=87233
regexMatchAll(content_SearchOn, regexPatternStr_MatchFor, ind_MatchFromPosition := 1) {
  ;~ stdout := FileOpen("*", "w")
  arr_matcher := []
  
  while (true)
  {
    ind_RegexGroupAll := RegExMatch(content_SearchOn, regexPatternStr_MatchFor, matcher, ind_MatchFromPosition)
    ; you cannot use `while (ind_RegexGroupAll != 0)`, cuz its would be evaluated after a Null match already pushed inside the array -> you must `break the loop` soon, before `arr_matcher.Push(matcher)`
    if (ind_RegexGroupAll == 0) { ; Zero is returned if the pattern is not found.
      break
    }
    arr_matcher.Push(matcher)
    
    ;~ ind_RegexGroupAll_Matcher := matcher.Pos ; Dont use this, if no match, all these `matcher.*` are null
    length_RegexGroupAll := matcher.Len
    ind_MatchFromPosition := ind_RegexGroupAll + length_RegexGroupAll
    ;~ stdout.WriteLine("ind_RegexGroupAll: " . ind_RegexGroupAll)
    ;~ stdout.WriteLine("ind_RegexGroupAll_Matcher: " . ind_RegexGroupAll_Matcher)
    ;~ stdout.WriteLine("length_RegexGroupAll: " . length_RegexGroupAll)
    ;~ stdout.WriteLine("ind_MatchFromPosition: " . ind_MatchFromPosition)
    
    if (length_RegexGroupAll == 0) { ; avoid zero-width match
      ind_MatchFromPosition += 1
      if (ind_MatchFromPosition > StrLen(content_SearchOn)) { ; avoid `ind_MatchFromPosition += 1` leads to out of bound -> inf loop (this happens if a zero-width match is at the end of `content_SearchOn`)
        ; @performance `StrLen(content_SearchOn)` can be improved
        break
      }
    }
    
  }
  
  return arr_matcher
}

; ;test; ; >>>>> Run Code Test
; ;test; content_SearchOn =
; ;test; (
; ;test; Mode 1 (default): Specify a variable in which to store the part of Haystack that matched the entire pattern. If the pattern is not found (that is, if the function returns 0), this variable and all array elements below are made blank.
; ;test; 
; ;test; If any capturing subpatterns are present inside NeedleRegEx, their matches are stored in a pseudo-array whose base name is OutputVar. For example, if the variable's name is Match, the substring that matches the first subpattern would be stored in Match1, the second would be stored in Match2, and so on. The exception to this is named subpatterns: they are stored by name instead of number. For example, the substring that matches the named subpattern (?P<Year>\d{4}) would be stored in MatchYear. If a particular subpattern does not match anything (or if the function returns zero), the corresponding variable is made blank.
; ;test; 
; ;test; Within a function, to create a pseudo-array that is global instead of local, declare the base name of the pseudo-array (e.g. Match) as a global variable prior to using it. The converse is true for assume-global functions. However, it is often also necessary to declare each element, due to a common source of confusion.
; ;test; )
; ;test; 
; ;test; regexPatternStr_MatchFor := "m`aO)b(.*?) " ; https://www.autohotkey.com/boards/viewtopic.php?t=50537&p=223767
; ;test; arr_matcher := regexMatchAll(content_SearchOn, regexPatternStr_MatchFor)
; ;test; 
; ;test; stdout := FileOpen("*", "w")
; ;test; for ind_matcher_curr, matcher_curr in arr_matcher 
; ;test; {
; ;test;   stdout.WriteLine(ind_matcher_curr . ": " . matcher_curr.Value)
; ;test; }
; ;test; 
; ;test; ; >>>>> Output
; ;test; ; >"E:\AutoHotkey\AutoHotkey.exe" /ErrorStdOut "C:\Users\Zlgtx\Desktop\AHK scripts\Test\Test.ahk"    
; ;test; ; 1: ble 
; ;test; ; 2: ble 
; ;test; ; 3: below 
; ;test; ; 4: bpatterns 
; ;test; ; 5: base 
; ;test; ; 6: ble's 
; ;test; ; 7: bstring 
; ;test; ; 8: bpattern 
; ;test; ; 9: be 
; ;test; ; 10: be 
; ;test; ; 11: bpatterns: 
; ;test; ; 12: by 
; ;test; ; 13: ber. 
; ;test; ; 14: bstring 
; ;test; ; 15: bpattern 
; ;test; ; 16: be 
; ;test; ; 17: bpattern 
; ;test; ; 18: ble 
; ;test; ; 19: bal 
; ;test; ; 20: base 
; ;test; ; 21: bal 
; ;test; ; 22: ble 
; ;test; ; 23: bal 
; ;test; ; >Exit code: 0    Time: 0.271
Nor.Z
  • 555
  • 1
  • 5
  • 13