Over a few years I've made modifications to this script. Is my updated version even wanted? Here's a screenshot. The big addon is the view on the right, which hopefully not only splits up the RegEx into parts, but editing the right side updates it in the original single line.

The replacement field can accept escaped chars, being `r`n and `t. This way you actually see what you would get from
AHK.
EDIT: Oh well. Here's what I have. Hopefully it's good enough for someone else to use if they want to.
Last Update: 10 April 2012
Code:
;Modifications by Era Scarecrow
; 20 March 2012: Added right side for visual breakdown of regex
; 1 April 2012: Added fix for | splitting with escapes. Spaces that can be
; confused in the right side for indentation now have non-capture groups to
; tell them apart. Those groups are removed under certain criteria.
; 5 April 2012: Added escape conversions allowing m`n) and others to work
; properly. Default converts all `r`n`t's to their \r\n\r except for options.
; 10 April 2012: cleaned up regex with anchors. (No functional difference)
;========================+
; Auto-Execution Section |
;==============================================================================
#NoEnv
#SingleInstance force
Sendmode Input
CreateMainGUI()
Return
;==============================================================================
;=========+
; HotKeys |
;==============================================================================
#IfWinActive AHK Regex Sandbox
!c::
Gui, Submit, NoHide
clipboard := (tabselection = "RegExMatch") ? mahkcode : rahkcode
return
;==============================================================================
;========================+
; RegExMatch Subroutines |
;==============================================================================
RegExMatchEval:
Gui, Submit, NoHide
; Clear all variables prefixed with "mre_"
ClearArray("mre_")
; Set non-empty defaults
mstartpos := mstartpos ? mstartpos : 1
; Do RegExMatch
mneedle := regex_escapes_fix(mneedle)
mfoundpos := RegExMatch(mhaystack, mneedle, mre_, mstartpos)
Gosub, DisplayRegExMatchResults
Gosub, DisplayRegExMatchCode
Gosub, DisplayExpandedRegex
return
DisplayRegExMatchResults:
moutput := "ErrorLevel: " . ErrorLevel . "`n"
. "FoundPos: " . mfoundpos . "`n"
mre_list := GetNonEmptyArrayVars("mre_")
If moutputvar
{
Loop, parse, mre_list, `,
{
moutput .= moutputvar . Substr(A_LoopField, 5) . ": """ . %A_LoopField% . """`n"
}
}
GuiControl, , mresults, %moutput%
return
DisplayRegExMatchCode:
StringReplace, mneedle_tmp, mneedle, ", "", All
mneedle_tmp := regex_escapes_fix(mneedle_tmp, 2)
regexmatchcode := "FoundPos := RegExMatch(haystack, """ . mneedle_tmp . """"
If moutputvar
regexmatchcode .= ", " . moutputvar
If mstartpos != 1
regexmatchcode .= (moutputvar ? "" : ", ") . ", " . mstartpos
regexmatchcode .= ")"
GuiControl, , mahkcode, %regexmatchcode%
return
RegExMatchNeedleExpanded:
Gui, Submit, NoHide
tmp := regexCompact(mneedleExpanded)
tmp := regex_escapes_fix(tmp, 2)
GuiControl, , mneedle, %tmp%
return
DisplayExpandedRegex:
ControlGetFocus, Focused, AHK Regex Sandbox
if (Focused != "Edit7") {
mneedle := regex_escapes_fix(mneedle, 2)
tmp := RegexReFormat(mneedle)
GuiControl, , mneedleExpanded, %tmp%
}
return
;==============================================================================
;==========================+
; RegExReplace Subroutines |
;==============================================================================
RegExReplaceEval:
Gui, Submit, NoHide
; Set non-empty defaults
rstartpos := rstartpos ? rstartpos : 1
rlimit := rlimit ? rlimit : -1
; Do RegExReplace
rneedle := regex_escapes_fix(rneedle)
rep := rreplacementtext
StringReplace, rep, rep, ``n, `n, All
StringReplace, rep, rep, ``r, `r, All
StringReplace, rep, rep, ``t, %a_tab%, All
rnewstr := RegExReplace(rhaystack, rneedle, rep, rcount, rlimit, rstartpos)
Gosub, DisplayRegExReplaceResults
Gosub, DisplayRegExReplaceCode
Gosub, DisplayExpandedReplaceRegex
return
DisplayRegExReplaceResults:
routput := "ErrorLevel: " . ErrorLevel . "`n"
If routputvar
routput .= routputvar . ": " . rcount . "`n"
routput .= "NewStr: " . rnewstr . "`n"
GuiControl, , rresults, %routput%
return
DisplayRegExReplaceCode:
StringReplace, rneedle_tmp, rneedle, ", "", All
rneedle_tmp := regex_escapes_fix(rneedle_tmp, 2)
regexreplacecode := "NewStr := RegExReplace(haystack, """ . rneedle_tmp . """"
If (rreplacementtext) or (routputvar) or (rlimit != -1) or (rstartpos != 1)
regexreplacecode .= ", " . ( rreplacementtext ? """" . rreplacementtext . """" : "" )
If routputvar or (rlimit != -1) or (rstartpos != 1)
regexreplacecode .= ", " . ( routputvar ? routputvar : "" )
If (rlimit != -1) or (rstartpos != 1)
regexreplacecode .= ", " . ( (rlimit != -1) ? rlimit : "" )
If (rstartpos != 1)
regexreplacecode .= ", " . rstartpos
regexreplacecode .= ")"
GuiControl, , rahkcode, %regexreplacecode%
return
RegExReplaceNeedleExpanded:
Gui, Submit, NoHide
tmp := regexCompact(rneedleExpanded)
tmp := regex_escapes_fix(tmp, 2)
GuiControl, , rneedle, %tmp%
return
DisplayExpandedReplaceRegex:
ControlGetFocus, Focused, AHK Regex Sandbox
if (Focused != "Edit16") {
tmp := regex_escapes_fix(rneedle, 2)
tmp := RegexReFormat(tmp)
GuiControl, , rneedleExpanded, %tmp%
}
return
;==============================================================================
;========================+
; Array-helper functions |
;==============================================================================
ClearArray(prefix)
{
global
lgv := ListGlobalVars()
Loop, parse, lgv, |
{
If (InStr(A_LoopField, prefix) = 1)
%A_LoopField% = ©¥®©¥®©¥®©¥®
}
}
GetNonEmptyArrayVars(prefix)
{
global
local varlist =
lgv := ListGlobalVars()
Loop, parse, lgv, |
{
If (InStr(A_LoopField, prefix) = 1) and (%A_LoopField% != "©¥®©¥®©¥®©¥®")
varlist .= A_LoopField . ","
}
StringTrimRight, varlist, varlist, 1
return varlist
}
;==============================================================================
;===========+
; GUI Stuff |
;==============================================================================
CreateMainGUI()
{
global
Gui, Add, Tab, x2 y2 w768 h500 +Theme vtabselection -background, RegExMatch|RegExReplace
Gui, Tab, RegExMatch
Gui, Font
Gui, Add, Text, x12 y42 w480 h15 +Backgroundtrans, Regular Expression (the "needle"):
Gui, Add, Text, x12 y97 w235 h15 +Backgroundtrans, Output Variable (defaults to ""):
Gui, Add, Text, x257 y97 w235 h15 +Backgroundtrans, Starting Position (defaults to 1):
Gui, Add, Text, x12 y152 w480 h15 +Backgroundtrans, Text to be searched (the "haystack"):
Gui, Add, Text, x12 y257 w480 h15 +Backgroundtrans, Results:
Gui, Add, Text, x12 y457 w480 h15 +Backgroundtrans, AHK Code:
Gui, Font, s10, courier new
Gui, Add, Edit, x12 y57 w480 h30 -VScroll vmneedle gRegExMatchEval,
Gui, Add, Edit, x12 y112 w230 h30 -VScroll vmoutputvar gRegExMatchEval, match
Gui, Add, Edit, x257 y112 w235 h30 -VScroll vmstartpos gRegExMatchEval,
Gui, Add, Edit, x12 y167 w480 h80 vmhaystack gRegExMatchEval,
Gui, Add, Edit, x12 y272 w480 h175 vmresults +readonly,
Gui, Font, s8, courier new
Gui, Add, Edit, x12 y472 w480 h20 vmahkcode +readonly
Gui, Add, Edit, x502 y32 w260 h460 vmneedleExpanded gRegExMatchNeedleExpanded,
Gui, Tab, RegExReplace
Gui, Font
Gui, Add, Text, x12 y42 w480 h15 +Backgroundtrans, Regular Expression (the "needle"):
Gui, Add, Text, x12 y97 w150 h15 +Backgroundtrans, Replacement Text (""):
Gui, Add, Text, x172 y97 w150 h15 +Backgroundtrans, Output Variable (""):
Gui, Add, Text, x332 y97 w75 h15 +Backgroundtrans, Limit (-1):
Gui, Add, Text, x417 y97 w75 h15 +Backgroundtrans, Startpos (1):
Gui, Add, Text, x12 y152 w480 h15 +Backgroundtrans, Text to be searched (the "haystack"):
Gui, Add, Text, x12 y257 w480 h15 +Backgroundtrans, Results:
Gui, Add, Text, x12 y457 w480 h15 +Backgroundtrans, AHK Code:
Gui, Font, s10, courier new
Gui, Add, Edit, x12 y57 w480 h30 -VScroll vrneedle gRegExReplaceEval,
Gui, Add, Edit, x12 y112 w150 h30 -VScroll vrreplacementtext gRegExReplaceEval,
Gui, Add, Edit, x172 y112 w150 h30 -VScroll vroutputvar gRegExReplaceEval, count
Gui, Add, Edit, x332 y112 w75 h30 -VScroll vrlimit gRegExReplaceEval,
Gui, Add, Edit, x417 y112 w75 h30 -VScroll vrstartpos gRegExReplaceEval,
Gui, Add, Edit, x12 y167 w480 h80 vrhaystack gRegExReplaceEval,
Gui, Add, Edit, x12 y272 w480 h175 vrresults +readonly,
Gui, Font, s8, courier new
Gui, Add, Edit, x12 y472 w480 h20 vrahkcode +readonly
Gui, Add, Edit, x502 y32 w260 h460 vrneedleExpanded gRegExReplaceNeedleExpanded,
; (mostly) generated using SmartGUI Creator 4.0
Gui, Show, xCenter yCenter h504 w772, AHK Regex Sandbox
}
GuiEscape:
GuiClose:
ExitApp
;==============================================================================
;==================+
; ListGlobalVars() |
; by Lexikos +====================================+
; http://www.autohotkey.com/forum/viewtopic.php?t=22692 |
;==============================================================================
ListGlobalVars()
{
static hwnd, hwndEdit, pSFW, pSW, bkpSFW, bkpSW
if !hwndEdit
{
dhw := A_DetectHiddenWindows
DetectHiddenWindows, On
Process, Exist
hwnd := WinExist("ahk_class AutoHotkey ahk_pid " ErrorLevel)
ControlGet, hwndEdit, Hwnd,, Edit1
DetectHiddenWindows, %dhw%
hmod := DllCall("GetModuleHandle", "str", "user32.dll")
pSFW := DllCall("GetProcAddress", "uint", hmod, "str", "SetForegroundWindow")
pSW := DllCall("GetProcAddress", "uint", hmod, "str", "ShowWindow")
DllCall("VirtualProtect", "uint", pSFW, "uint", 8, "uint", 0x40, "uint*", 0)
DllCall("VirtualProtect", "uint", pSW, "uint", 8, "uint", 0x40, "uint*", 0)
bkpSFW := NumGet(pSFW+0, 0, "int64")
bkpSW := NumGet(pSW+0, 0, "int64")
}
NumPut(0x0004C200000001B8, pSFW+0, 0, "int64") ; return TRUE
, NumPut(0x0008C200000001B8, pSW+0, 0, "int64") ; return TRUE
, DllCall("SendMessage", "uint", hwnd, "uint", 0x111, "uint", 65407, "uint", 0)
, NumPut(bkpSFW, pSFW+0, 0, "int64")
, NumPut(bkpSW, pSW+0, 0, "int64")
ControlGetText, text,, ahk_id %hwndEdit%
RegExMatch(text, "sm)(?<=^Global Variables \(alphabetical\)`r`n-{50}`r`n).*", text)
pos = 1
Loop {
pos := RegExMatch(text, "m)^[\w#@$?\[\]]+(?=\[\d+ of \d+\]: )", var, pos)
if ! pos
break
list .= var "|"
pos += StrLen(var)
}
return SubStr(list, 1, -1)
}
;==============================================================================
;added functions by Era Scarecrow
;remove comments and unwanted whitespace, make a neat one-liner.
regexCompact(text){
text := regexReplace(text, "`amS)\s+##.*+$")
text := regexReplace(text, "`amS)\s+$")
text := regexReplace(text, "`amS)^\s+")
text := regexReplace(text, "[\t\r\n]++")
;#convert whitespace non-capture groups to spaces (If it doesn't have a conditional)
text := regexReplace(text, "\(\?:(\s+([+*?]{0,2}|\{\d*+,?\d*+\}[+?]?))\)", "$1")
return text
}
regexReFormat(text) {
global regexFmt
;first remove any indentation that might be there, rebuild.
tmp := regexCompact(text)
;###Regex ReFormat
tmp := regexReplace(tmp, "((?<!\\)(\\\\)*+\((?!([^][\\\r\n]*+|\\.)*\])(?:\?(?::|<?[=!]|<\w+>))?)", "`r`n$1`r`n")
tmp := regexReplace(tmp, "(?<!\\)((?:\\\\)*)(\)((?:\{\d*,?\d\}|[+*?])?[+*?]?)?)(?!([^][\\\r\n]*|\\.)*\])", "$1`r`n$2`r`n")
tmp := regexReplace(tmp, "(?<!\\)((?:\\\\)*)\|", "$1`r`n|`r`n")
tmp := regexReplace(tmp, "(?<!\\)((?:\\\\)*)(\[\^?\]?\[?(?:[^][\\\r\n]*+|\\.)*\])", "$1`r`n$2")
;#greedy/nongreedy modifiers
tmp := regexReplace(tmp, "((?<!\\)(\\\\)*(\{\d*+,?\d*+\}[\+\?]?|[\*\+\?][\+\?]?)\+?)(?<!\(\?)(?!([^][\\\r\n]*|\\.)\])", "$1`r`n")
;#deal with modifiers
tmp := regexReplace(tmp, "^([\w``]++)\r?\n\)", "$1)")
tmp := regexReplace(tmp, "[\r\n]++", "`r`n")
;#combine groups that have no length modifiers.
tmp := regexReplace(tmp, "`am)^(\((?:\?(?:<?[!=]|[:<]))?)[\r\n]*(?!\()((?:[^][\\\r\n*+?]++|\\.)+)[\r\n]*\)", "$1$2)")
;#deal with leading/trailing spaces. Add into non-capture groups.
tmp := regexReplace(tmp, "`am)^\(\?:\r?\n( +([+*?]{0,2}|\{\d*+,?\d*+\}[+?]?))\r?\n\)", "(?:$1)")
tmp := regexReplace(tmp, "`am)^( +(?:[+?*]+|\{\d*+,?\d*+\}[+?]?)?)", "(?:$1)")
tmp := regexReplace(tmp, "`am)( +)$", "(?:$1)")
;now for indentation.
i =
text =
loop, parse, tmp, `n, `r
{
if (substr(A_LoopField,1,1) = ")")
i := substr(i, 5)
if (substr(A_LoopField,1,1) = "|")
text .= substr(i, 5) . A_LoopField . "`r`n"
else
text .= i . A_LoopField . "`r`n"
if (subStr(A_loopfield, 1, 1) == "(" && regexMatch(A_LoopField,"^\((.*?)(?<!\\)((\\\\)*\)((?:\{\d*+,?\d*+\}|[+*?])?[+?]?)?)") == 0)
i .= " "
}
return text
}
;if isNeedle = 1, then it's the actual input regex Match/replace will use
;if isNeedle = 2, as a text version we can use in our source code.
regex_escapes_fix(reg, isNeedle = 1){
;bulk convert to escaped chars (normal escaped)
StringReplace, reg, reg, ``n, \n, All
StringReplace, reg, reg, ``r, \r, All
StringReplace, reg, reg, ``a, \a, All
StringReplace, reg, reg, ``t, \t, All
;convert raw versions to their escaped equivs
StringReplace, reg, reg, %a_tab%, \t, All
StringReplace, reg, reg, `n, \n, All
StringReplace, reg, reg, `r, \r, All
StringReplace, reg, reg, `a, \a, All
;convert escaped to real if it's part of a needle and the 'options'
if (isNeedle = 1) {
reg := RegexReplace(reg, "^([^()]*)\\r([^()]*)\)", "$1`r$2)")
reg := RegexReplace(reg, "^([^()]*)\\n([^()]*)\)", "$1`n$2)")
reg := RegexReplace(reg, "^([^()]*)\\a([^()]*)\)", "$1`a$2)")
}
;convert escaped (source) if it's part of the options
if (isNeedle = 2) {
reg := RegexReplace(reg, "^([^()]*)\\r([^()]*)\)", "$1``r$2)")
reg := RegexReplace(reg, "^([^()]*)\\n([^()]*)\)", "$1``n$2)")
reg := RegexReplace(reg, "^([^()]*)\\a([^()]*)\)", "$1``a$2)")
}
return reg
}