RegEx Tester

Post your working scripts, libraries and tools for AHK v1.1 and older
toralf
Posts: 868
Joined: 27 Apr 2014, 21:08
Location: Germany

RegEx Tester

10 Jun 2020, 05:27

This is an updated version of the RegEx Tester by Robert Ryan's from 2012

2020-06-10
- GUI resizable
- Errorlevel text is show when needle is wrong
- fixed: Match results were shown from previous correct needle when needle was wrong
- RegEx Option `n, `r and `a are now handled via checkboxes, since edit control doesn't handle them well

2020-06-15
- added ability to have Needles broken up in multiple lines with comments, because I like to document/comment my more complex needles like this

Code: Select all

FunctionRE :="
  ( Join LTrim Comment  ;$1 the whole line will be a match
        OS)(*UCP)       ;Study and Unicode (for \w)
        ^               ;at the start of line
        ([\w$#@]+)      ;$1 one or more characters (A-Za-z0-9_) or #, $, @  (all allowed characters in variable names)
        \(              ;a '('
  )"

Code: Select all

;
; Original Script can be found at:
; http://www.autohotkey.com/board/topic/81045-regular-expression-tester/
; this script can be found at:
; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=77133#p334841
;

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

/*
    Regex Tester - A front end for testing Perl Compatible Regular Expressions.
                   The results update in realtime and any setting or expression
                   errors are highlighted in red.
                   
                   Alt+C will copy the currently displayed expression to the Clipboard.
    
    Version 1.0
    from 5-29-2012
    By Robert Ryan
    
    updated 6.10.2020
    by toralf
    - GUI resizable
    - Errorlevel text is show when needle is wrong
    - fixed: Match results were shown from previous correct needle when needle was wrong
    - RegEx Option `n, `r and `a are now handled via checkboxes, since edit control doesn't handle them well

    updated 15.6.2020
    by toralf
    - added ability to have Needles broken up in multiple lines with comments
    
*/

; AutoeExecute
    #NoEnv
    #SingleInstance force

    gosub MakeGui
    gosub UpdateMatch
    gosub UpdateReplace
    Gui Show, , RegEx Tester - v15.06.2020
return

#IfWinActive Regex Tester
!c::
    Gui Submit, NoHide
    ClipBoard := (TabSelection = "RegExMatch") ? mNeedle : rNeedle
    MsgBox, 64, RegEx Copied, %Clipboard% has been copied to the Clipboard, 3
return

GuiEscape:
GuiClose:
    ExitApp
return

RemoveComments(Line){
  If !(Pos := InStr(Trim(Line), ";"))
    Return Line             ; no quote character in this line

  If (Pos = 1)
    Return                  ; whole line is pure comment

  ;remove comments (first clean line of quotes strings)
  If (Pos := RegExMatch(RemoveQuotedStrings(Line), "\s+;.*$"))
    Line := SubStr(Line, 1, Pos - 1)

  Return Line
}

RemoveQuotedStrings(Line){
  ;the concept how to remove quoted strings was taken from CoCo's ListClasses script (line 77; http://ahkscript.org/boards/viewtopic.php?p=43349#p42793)
  ;replace quoted strings with dots and dashes to keep length of line constant, and that other character positions do not change
  static q := Chr(34)       ; quote character

  ;Replace quoted literal strings             1) replace two consecutive quotes with dots
  CleanLine := StrReplace(Line, q . q, "..")

  Pos := 1                                 ;  2) replace ungreedy strings in quotes with dashes
  Needle := q . ".*?" . q
  While Pos := RegExMatch(CleanLine, Needle, QuotedString, Pos){
    ReplaceString =
    Loop, % StrLen(QuotedString)
       ReplaceString .= "-"
    CleanLine := RegExReplace(CleanLine, Needle, ReplaceString, Count, 1, Pos)
  }
  Return CleanLine
}

; This is called any time any of the edit boxes on the RegExMatch tab are changed.
UpdateMatch:
    Gui Submit, NoHide
    
    if not IsInteger(mStartPos) {
        mStartPos := 1
        Gui Font, cRed 
        GuiControl Font, mStartPos
    }else {
        Gui Font, cDefault
        GuiControl Font, mStartPos
    }
    
    ;when needle is broken in several lines comments are stripped off every line and lines with text are concatenated
    LineArray := StrSplit(mNeedle, "`n", "`r")
    If (LineArray.MaxIndex() > 1) {
      tmp =
      For i, Line in LineArray
        If (CleanLine := RemoveComments(Trim(Line)))
          tmp .= CleanLine
      mNeedle := tmp
    }
    ; Set Needle to return an object ( O maybe set even twice)
    mNeedle := RegExReplace(mNeedle, "^(\w*)\)", "O$1)", cnt)
    if (! cnt) {
        mNeedle := "O)" mNeedle
    }

    If mLF
      mNeedle := "`n" mNeedle
    If mCR
      mNeedle := "`r" mNeedle
    If mAnyCRLF
      mNeedle := "`a" mNeedle    

    Match =
    FoundPos := RegExMatch(mHaystack, mNeedle, Match, mStartPos)
    if (ErrLvl := ErrorLevel) {
        Gui Font, cRed 
        GuiControl Font, mNeedle
        ResultText := "FoundPos: " FoundPos "`n" 
                    . "ErrorLevel: `n" ErrLvl "`n`n"
                    . "Needle: `n""" mNeedle """`n`n"
    }else {
        Gui Font, cDefault
        GuiControl Font, mNeedle
        ResultText := "FoundPos: " FoundPos "`n"
        ResultText .= "Match: " Match.Value() "`n"
                   . "Needle: `n""" mNeedle """`n`n"
        Loop % Match.Count() {
            ResultText .= "Match["
            ResultText .= (Match.Name[A_Index] = "") 
                        ? A_Index 
                        :  Match.Name[A_Index] 
            ResultText .= "]: " Match[A_Index] "`n"
                       
        }
    }
    
    GuiControl, , mResult, %ResultText%
return

; This is called any time any of the edit boxes on the RegExReplace tab are changed.
UpdateReplace:
    Gui Submit, NoHide
    
    If not IsInteger(rStartPos) {
        rStartPos := 1
        Gui Font, cRed 
        GuiControl Font, rStartPos
    }Else {
        Gui Font, cDefault
        GuiControl Font, rStartPos
    }
    
    If not IsInteger(rLimit) {
        rLimit := -1
        Gui Font, cRed 
        GuiControl Font, rLimit
    }Else {
        Gui Font, cDefault
        GuiControl Font, rLimit
    }
    
    ;when needle is broken in several lines comments are stripped off every line and lines with text are concatenated
    LineArray := StrSplit(rNeedle, "`n", "`r")
    If (LineArray.MaxIndex() > 1) {
      tmp =
      For i, Line in LineArray
        If (CleanLine := RemoveComments(Trim(Line)))
          tmp .= CleanLine
      rNeedle := tmp
    }

    If rLF
      rNeedle := "`n" rNeedle
    If rCR
      rNeedle := "`r" rNeedle
    If rAnyCRLF
      rNeedle := "`a" rNeedle    
    
    NewStr := RegExReplace(rHaystack, rNeedle, rReplacement, rCount, rLimit, rStartPos)
    If (ErrLvl := ErrorLevel) {
        Gui Font, cRed 
        GuiControl Font, rNeedle
        ResultText := "Count: " rCount "`n" 
                    . "ErrorLevel: `n" ErrLvl "`n`n"
                    . "Needle: `n""" rNeedle """`n`n"
    }Else {
        Gui Font, cDefault
        GuiControl Font, rNeedle
        ResultText := "Count: " rCount "`n" 
                    . "NewStr: `n" NewStr
    }
    
    GuiControl, , rResult, %ResultText%
return

MakeGui:
    Gui, +ReSize +MinSize
    Gui Font, s10, Consolas
    Gui Add, Tab2, r25 w430 vTabSelection, RegExMatch|RegExReplace
    
    Gui Tab, RegExMatch
        Gui Add, Text, , Text to be searched:
        Gui Add, Edit, r10 w400 vmHaystack gUpdateMatch
        Gui Add, Text, Section vmTxtRegEx, Regular Expression:  Option
        Gui Add, Checkbox, x+2 vmLF gUpdateMatch, ``n
        Gui Add, Checkbox, x+2 vmCR gUpdateMatch, ``r
        Gui Add, Checkbox, x+2 vmAnyCRLF gUpdateMatch, ``a
        Gui Add, Edit, xs r5 w305 vmNeedle gUpdateMatch
        Gui Add, Text, x+15 ys vmTxtStart, Start: (1)
        Gui Add, Edit, r1 w75 vmStartPos gUpdateMatch, 1
        Gui Add, Text, xs vmTxtResult, Results:
        Gui Add, Edit, r14 w400 +readonly -TabStop vmResult
        
    Gui Tab, RegExReplace
        Gui Add, Text, , Text to be searched:
        Gui Add, Edit, r10 w400 vrHaystack gUpdateReplace, 
        Gui Add, Text, Section vrTxtRegEx, Regular Expression:  Option
        Gui Add, Checkbox, x+2 vrLF gUpdateReplace, ``n
        Gui Add, Checkbox, x+2 vrCR gUpdateReplace, ``r
        Gui Add, Checkbox, x+2 vrAnyCRLF gUpdateReplace, ``a
        Gui Add, Edit, xs r5 w305 vrNeedle gUpdateReplace, 
        Gui Add, Text, vrTxtReplace, Replacement Text:
        Gui Add, Edit, r2 w305 vrReplacement gUpdatereplace,
        Gui Add, Text,  vrTxtResult, Results:
        Gui Add, Edit, r10 w400 +readonly -TabStop vrResult
        Gui Add, Text, ys xs+320 Section vrTxtStart, Start: (1)
        Gui Add, Edit, r1 w75 vrStartPos gUpdateReplace, 1
        Gui Add, Text, xs y+15 vrTxtLimit, Limit: (-1)
        Gui Add, Edit, r1 w75 vrLimit gUpdateReplace, -1
return

IsInteger(str) {
    if str is integer
        return true
    else
        return false
}

GuiSize(GuiHwnd, EventInfo, Width, Height){
  AutoXYWH("wh", "TabSelection")
  AutoXYWH("wh0.333", "mHaystack", "rHaystack")
  AutoXYWH("y0.3333", "mTxtRegEx", "rTxtRegEx", "mLF", "mCR", "mAnyCRLF", "rLF", "rCR", "rAnyCRLF")
  AutoXYWH("xy0.3333", "mTxtStart", "rTxtStart", "mStartPos", "rStartPos", "rTxtLimit", "rLimit", "", "")
  AutoXYWH("y0.3333wh0.333", "mNeedle", "")
  AutoXYWH("y0.6666", "mTxtResult", "rTxtResult")
  AutoXYWH("y0.6666wh0.333", "mResult", "rResult")
  
  AutoXYWH("y0.3333wh0.166", "rNeedle")
  AutoXYWH("y0.5wh0.166", "rReplacement")
  AutoXYWH("y0.5", "rTxtReplace", "")
}

AutoXYWH(DimSize, cList*){   ;https://www.autohotkey.com/boards/viewtopic.php?t=1079
  Static cInfo := {}

  If (DimSize = "reset")
    Return cInfo := {}

  For i, ctrl in cList {
    ctrlID := A_Gui ":" ctrl
    If !cInfo.hasKey(ctrlID) {
      ix := iy := iw := ih := 0	
      GuiControlGet i, %A_Gui%: Pos, %ctrl%
      MMD := InStr(DimSize, "*") ? "MoveDraw" : "Move"
      fx := fy := fw := fh := 0
      For i, dim in (a := StrSplit(RegExReplace(DimSize, "i)[^xywh]"))) 
        If !RegExMatch(DimSize, "i)" . dim . "\s*\K[\d.-]+", f%dim%)
          f%dim% := 1

      If (InStr(DimSize, "t")) {
        GuiControlGet hWnd, %A_Gui%: hWnd, %ctrl%
        hParentWnd := DllCall("GetParent", "Ptr", hWnd, "Ptr")
        VarSetCapacity(RECT, 16, 0)
        DllCall("GetWindowRect", "Ptr", hParentWnd, "Ptr", &RECT)
        DllCall("MapWindowPoints", "Ptr", 0, "Ptr", DllCall("GetParent", "Ptr", hParentWnd, "Ptr"), "Ptr", &RECT, "UInt", 1)
        ix := ix - NumGet(RECT, 0, "Int")
        iy := iy - NumGet(RECT, 4, "Int")
      }

      cInfo[ctrlID] := {x:ix, fx:fx, y:iy, fy:fy, w:iw, fw:fw, h:ih, fh:fh, gw:A_GuiWidth, gh:A_GuiHeight, a:a, m:MMD}
    } Else {
      dgx := dgw := A_GuiWidth - cInfo[ctrlID].gw, dgy := dgh := A_GuiHeight - cInfo[ctrlID].gh
      Options := ""
      For i, dim in cInfo[ctrlID]["a"]
        Options .= dim (dg%dim% * cInfo[ctrlID]["f" . dim] + cInfo[ctrlID][dim]) A_Space
      GuiControl, % A_Gui ":" cInfo[ctrlID].m, % ctrl, % Options
} } }
Screenshots
Last edited by toralf on 15 Jun 2020, 07:58, edited 1 time in total.
ciao
toralf
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: RegEx Tester

14 Jun 2020, 16:09

Very nice! :thumbup:
Thanks for sharing.
toralf
Posts: 868
Joined: 27 Apr 2014, 21:08
Location: Germany

Re: RegEx Tester

15 Jun 2020, 07:58

2020-06-15
- added ability to have Needles broken up in multiple lines with comments
ciao
toralf
teadrinker
Posts: 4330
Joined: 29 Mar 2015, 09:41
Contact:

Re: RegEx Tester

16 Jun 2020, 11:50

toralf wrote: RegEx Option `n, `r and `a are now handled via checkboxes, since edit control doesn't handle them well
The script still works incorrectly, since the pattern may contain `n or `r or `t.
 
 Image

Code: Select all

text =
(
1
2
3
)
MsgBox, % RegExReplace(text, "`n") ; 123
toralf
Posts: 868
Joined: 27 Apr 2014, 21:08
Location: Germany

Re: RegEx Tester

16 Jun 2020, 16:55

Do you have an idea how this could be solved?
If not, I guess then our best option is to use the key code for `n for it.
ciao
toralf
teadrinker
Posts: 4330
Joined: 29 Mar 2015, 09:41
Contact:

Re: RegEx Tester

16 Jun 2020, 17:04

I think, the best solution is RegEx. :) I'll try to solve this issue.
teadrinker
Posts: 4330
Joined: 29 Mar 2015, 09:41
Contact:

Re: RegEx Tester

17 Jun 2020, 10:29

I seem to have fixed the rbrtryn's version:

Code: Select all

/*
    Regex Tester - A front end for testing Perl Compatible Regular Expressions.
                   The results update in realtime and any setting or expression
                   errors are highlighted in red.
                   
                   Alt+C will copy the currently displayed expression to the Clipboard.
    
    Version 1.0
    Last Update 5-29-2012
    By Robert Ryan
*/

; AutoeExecute
    #NoEnv
    #SingleInstance force

    gosub MakeGui
    gosub UpdateMatch
    gosub UpdateReplace
    Gui Show, , Regex Tester
return

#IfWinActive Regex Tester
!c::
    Gui Submit, NoHide
    ClipBoard := (TabSelection = "RegExMatch") ? mNeedle : rNeedle
    MsgBox, 64, RegEx Copied, %Clipboard% has been copied to the Clipboard, 3
return

GuiEscape:
GuiClose:
    ExitApp
return

; This is called any time any of the edit boxes on the RegExMatch tab are changed.
UpdateMatch:
    Gui Submit, NoHide
    
    if not IsInteger(mStartPos) {
        mStartPos := 1
        Gui Font, cRed 
        GuiControl Font, mStartPos
    }
    else {
        Gui Font, cDefault
        GuiControl Font, mStartPos
    }
    
    ; Set Needle to return an object
    mNeedle := RegExReplace(mNeedle, "^([\w``]+?)\)", "O$1)", cnt)
    if !cnt {
        mNeedle := "O)" mNeedle
    }
    mNeedle := RegExReplace(mNeedle, """""", """")
    FoundPos := RegExMatch(ReplaceSpecChar(mHaystack), ReplaceSpecChar(mNeedle), Match, mStartPos)
    if (ErrorLevel) {
        Gui Font, cRed 
        GuiControl Font, mNeedle
    }
    else {
        Gui Font, cDefault
        GuiControl Font, mNeedle
    }
    
    ResultText := "FoundPos: " FoundPos "`n"
    ResultText .= "Match: " Match.Value() "`n"
    Loop % Match.Count() {
        ResultText .= "Match["
        ResultText .= (Match.Name[A_Index] = "") 
                    ? A_Index 
                    :  Match.Name[A_Index] 
        ResultText .= "]: " Match[A_Index] "`n"
    }
    GuiControl, , mResult, %ResultText%
return

; This is called any time any of the edit boxes on the RegExReplace tab are changed.
UpdateReplace:
    Gui Submit, NoHide
    
    if not IsInteger(rStartPos) {
        rStartPos := 1
        Gui Font, cRed 
        GuiControl Font, rStartPos
    }
    else {
        Gui Font, cDefault
        GuiControl Font, rStartPos
    }
    
    if not IsInteger(rLimit) {
        rLimit := -1
        Gui Font, cRed 
        GuiControl Font, rLimit
    }
    else {
        Gui Font, cDefault
        GuiControl Font, rLimit
    }
    rNeedle := RegExReplace(rNeedle, """""", """")
    NewStr := RegExReplace(ReplaceSpecChar(rHaystack), ReplaceSpecChar(rNeedle), rReplacement, rCount, rLimit, rStartPos)
    if (ErrorLevel) {
        Gui Font, cRed 
        GuiControl Font, rNeedle
    }
    else {
        Gui Font, cDefault
        GuiControl Font, rNeedle
    }
    
    ResultText := "Count: " rCount "`n"
    ResultText .= "NewStr: `n" NewStr "`n"
    
    GuiControl, , rResult, %ResultText%
return

MakeGui:
    Gui Font, s10, Consolas
    Gui Add, Tab2, r25 w400 vTabSelection, RegexMatch|RegexReplace
    
    Gui Tab, RegexMatch
        Gui Add, Text, , Text to be searched:
        Gui Add, Edit, r12 w370 vmHaystack gUpdateMatch
        Gui Add, Text, Section, Regular Expression:
        Gui Add, Edit, r2 w275 vmNeedle gUpdateMatch
        Gui Add, Text, x+15 ys, Start: (1)
        Gui Add, Edit, r1 w75 vmStartPos gUpdateMatch, 1
        Gui Add, Text, xs, Results:
        Gui Add, Edit, r14 w370 +readonly -TabStop vmResult
        
    Gui Tab, RegexReplace
        Gui Add, Text, , Text to be searched:
        Gui Add, Edit, r10 w370 vrHaystack gUpdateReplace
        Gui Add, Text, w275 Section, Regular Expression:
        Gui Add, Edit, r2 w275 vrNeedle gUpdateReplace
        Gui Add, Text, , Replacement Text:
        Gui Add, Edit, r2 w275 vrReplacement gUpdatereplace
        Gui Add, Text, , Results:
        Gui Add, Edit, r12 w370 +readonly -TabStop vrResult
        Gui Add, Text, ys xs+290 Section, Start: (1)
        Gui Add, Edit, r1 w75 vrStartPos gUpdateReplace, 1
        Gui Add, Text, xs y+35 , Limit: (-1)
        Gui Add, Edit, r1 w75 vrLimit gUpdateReplace, -1
return

IsInteger(str) {
    if str is integer
        return true
    else
        return false
}

ReplaceSpecChar(text, mode := false) {
   if mode {
      for k, v in [["a", "`a"], ["n", "`n"], ["r", "`r"], ["t", "`t"]] {
         if InStr(text, v[1])
            Return v[2]
      }
   }
   else {
      while RegExMatch(text, "sO)(.*?(?<!``)(?:````)*)(``[anrt]|$)", m, m ? m.Pos + m.Len : 1) {
         if (m[0] = "")
            break
         else
            newText .= m[1] . ReplaceSpecChar(m[2], true)
      }
      Return newText
   }
}
dbareis
Posts: 39
Joined: 04 Feb 2022, 17:57

Re: RegEx Tester

12 Sep 2022, 01:14

I have got a perfectly working regular expression working in regex101.com using options /gm

I add "Um)" to the start of the regexp and it is as if the "m" is not working at all in the tester and probably also AHK v1... with "m)" the "^" and "$" seem anchored to the start and end of the string, not lines as expected. Also "." matched line termination characters!
I've cobbled together something that works by avoiding the "^" and "$" characters.
teadrinker
Posts: 4330
Joined: 29 Mar 2015, 09:41
Contact:

Re: RegEx Tester

12 Sep 2022, 11:23

Do you have a question? :)
User avatar
oldbrother
Posts: 273
Joined: 23 Oct 2013, 05:08

Re: RegEx Tester

30 Dec 2022, 09:19

Nice! Thanks! :thumbup:

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 160 guests