;================================================================= ; Description: Testing Regular Expressions on the fly ; Requirement(s): Autoit 3.3.14.5 (2018) ; Author(s): YDY (Lazycat), thanks to w0uter for ideas and parts of code ; Modified: pixelsearch ; Version: 2.5r (11 nov 2024) ;================================================================= #include #include #include #include #include #include Global $hDll = DllOpen("user32.dll") ; for DllCall's in _TrackPopupMenu() : purpose is not open/close Dll at each call (on-line help) Global $_g_bWasAChange = True ; mLipok, cf Func WM_COMMAND() Global $nMode = 0, $APP_VER = "2.5r" Global $sIniFile = @ScriptDir & "\" & StringTrimRight(@ScriptName, 4) & ".ini" Global $sTxtFile = StringTrimRight($sIniFile, 4) & ".txt" ; read/write "match text" edit control in a separate txt file (no more size limit) Global $aInfo, $mPos, $nColor, $sOldResult, $sOldCount #Region ### START Koda GUI section ### Form=RegExpQuickTester.kxf Global $hGUI = GUICreate("RegExp Quick Tester " & $APP_VER, 460, 598, -1, -1, _ BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX), _ $WS_EX_ACCEPTFILES) ; accept to Maximize & Resize the GUI, also accept drag & drop Global $aGUIInitPos = WinGetPos($hGUI) ; see Func WM_GETMINMAXINFO ;========== $grpMatch = GUICtrlCreateGroup("Match Text", 4, 6, 449, 145) $ebTest = GUICtrlCreateEdit("", 12, 23, 434, 121, BitOR($ES_WANTRETURN, $WS_VSCROLL)) ; no horizontal scrollbar ; $ebTest = GUICtrlCreateEdit("", 12, 23, 434, 121) ; user may prefer this line, in case he needs an horizontal scrollbar GUICtrlSetFont(-1, 9, 400, 0, "Courier New") GUICtrlSetState(-1, $GUI_DROPACCEPTED) ; drag & drop accepted in "match text" edit control GUICtrlSendMsg($ebTest, $EM_LIMITTEXT, -1, 0) ; added to allow unlimited text size in edit control : ini file won't store this control anymore, a separate txt file will. GUICtrlCreateGroup("", -99, -99, 1, 1) ;========== $grpExpressions = GUICtrlCreateGroup("Expressions (right click for menu)", 4, 156, 449, 145, -1, $WS_EX_TRANSPARENT) $tabExpr = GUICtrlCreateTab(8, 174, 442, 121, BitOR($TCS_BUTTONS, $TCS_FLATBUTTONS, $TCS_FOCUSONBUTTONDOWN)) GUICtrlSetFont(-1, 8, 400, 0, "MS Sans Serif") GUICtrlSetResizing(-1, $GUI_DOCKAUTO) $TabSheet0 = GUICtrlCreateTabItem("Search Pattern") $ebRegExp = GUICtrlCreateEdit("", 12, 201, 434, 90, BitOR($ES_WANTRETURN,$WS_VSCROLL)) GUICtrlSetFont(-1, 11, 400, 0, "Lucida Console") $TabSheet1 = GUICtrlCreateTabItem("Replace Pattern") $ebRegExpReplace = GUICtrlCreateEdit("", 12, 201, 434, 90, BitOR($ES_WANTRETURN,$WS_VSCROLL)) GUICtrlSetFont(-1, 11, 400, 0, "Lucida Console") $TabSheet2 = GUICtrlCreateTabItem("Result Prefix") $ebResultPrefix = GUICtrlCreateEdit("", 12, 201, 434, 90, BitOR($ES_WANTRETURN,$WS_VSCROLL)) GUICtrlSetFont(-1, 11, 400, 0, "Lucida Console") $TabSheet3 = GUICtrlCreateTabItem("Result Suffix") $ebResultSuffix = GUICtrlCreateEdit("", 12, 201, 434, 90, BitOR($ES_WANTRETURN,$WS_VSCROLL)) GUICtrlSetFont(-1, 11, 400, 0, "Lucida Console") $TabSheet4 = GUICtrlCreateTabItem("Personal") $ebPersonal = GUICtrlCreateEdit("", 12, 201, 434, 90, BitOR($ES_WANTRETURN,$WS_VSCROLL)) GUICtrlSetFont(-1, 11, 400, 0, "Lucida Console") GUICtrlSendMsg($ebPersonal, $EM_LIMITTEXT, -1, 0) ; Added to allow 'unlimited' text size in edit control (10/02/2024) ; Purpose is to bypass the 30.000 characters (default) though it won't be really ; unlimited at all (see IniWrite notes in main loop when user wants to end the script) GUICtrlCreateTabItem("") GUICtrlCreateGroup("", -99, -99, 1, 1) ; purpose of $Tab_Highlight[3][2] is to highlight a TabItem if its Edit control contains something (or don't highlight if it's empty) Global $Tab_Highlight[3][2] = [[$ebRegExpReplace], [$ebResultPrefix], [$ebResultSuffix]] ; Col 1 = False (not highlited) ;========== $grpResults = GUICtrlCreateGroup("Result", 4, 304, 449, 208) $lblCount = GUICtrlCreateLabel("", 12, 492, 300, 17) ; width increased to 300 (in case additional infos). Possible to increase => 434 $ebResult = GUICtrlCreateEdit("", 12, 324, 434, 164, BitOR($WS_HSCROLL, $WS_VSCROLL, $ES_READONLY, $WS_TABSTOP)) GUICtrlSetFont(-1, 9, 400, 0, "Courier New") GUICtrlCreateGroup("", -99, -99, 1, 1) ;========== $grpBehaviour = GUICtrlCreateGroup("Options", 4, 514, 329, 78) GUICtrlCreateLabel("Mode:", 16, 536, 34, 17) $cbMode = GUICtrlCreateCombo("", 56, 532, 265, 25, BitOR($CBS_DROPDOWNLIST,$CBS_AUTOHSCROLL)) GUICtrlSetData(-1, "0 - Return 0/1|1 - Return array of matches|2 - Return array of matches with full match|3 - Return array of global matches|4 - Return array of arrays of global matches") GUICtrlCreateLabel("Replace count:", 16, 564, 77, 17) $ibRepCount = GUICtrlCreateInput("0", 96, 560, 72, 21, BitOr($GUI_SS_DEFAULT_INPUT, $ES_NUMBER)) $udRepCount = GUICtrlCreateUpdown($ibRepCount) GUICtrlSetLimit(-1, 16384, 0) $cbLineNum = GUICtrlCreateCheckbox("Show group numbers", 201, 562, 127, 17) GUICtrlCreateGroup("", -99, -99, 1, 1) ;========== $btnCode = GUICtrlCreateButton("Code", 370, 514, 81, 25) $btnClear = GUICtrlCreateButton("Clear", 370, 543, 81, 25) $btnClose = GUICtrlCreateButton("Close", 370, 572, 81, 25) ;========== ; $lblDummy = GUICtrlCreateLabel("", 336, 552, 1, 1) ; 1 pixel size ! Good luck to click on it in the GUI :) $lblDummy = GUICtrlCreateDummy() ; works fine too for associating a context menu to a dummy control. Keep same variable names so no other change needed $lblDummycontext = GUICtrlCreateContextMenu($lblDummy) $hDummycontext = GUICtrlGetHandle($lblDummyContext) ; for function _TrackPopupMenu() ; 25th march 2023 : context menu prepared in a separate function _PrepareContextMenu() Global $idMenu_Start, $idMenu_End ; +++ _PrepareContextMenu() ;========== GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### ; Reload recent data $nMode = Number(IniRead($sIniFile, "Main", "Mode", 0)) GUICtrlSendMsg($cbMode, $CB_SETCURSEL, $nMode, 0) GUICtrlSetState($cbLineNum, IniRead($sIniFile, "Main", "LineNum", 1)) GUICtrlSetData($ibRepCount, IniRead($sIniFile, "Main", "ReplaceCount", 0)) GUICtrlSetData($ebRegExp, BinaryToString(IniRead($sIniFile, "Main", "Pattern", ""), 4)) ; 4 = $SB_UTF8 (binary data is UTF8) GUICtrlSetData($ebRegExpReplace, BinaryToString(IniRead($sIniFile, "Main", "Replace", ""), 4)) GUICtrlSetData($ebResultPrefix, BinaryToString(IniRead($sIniFile, "Main", "Prefix", ""), 4)) GUICtrlSetData($ebResultSuffix, BinaryToString(IniRead($sIniFile, "Main", "Suffix", ""), 4)) GUICtrlSetData($ebPersonal, BinaryToString(IniRead($sIniFile, "Main", "Personal", ""), 4)) GUICtrlSetData($ebTest, FileRead($sTxtFile)) GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") ; mLipok GUIRegisterMsg($WM_GETMINMAXINFO, "WM_GETMINMAXINFO") While 1 $aInfo = GUIGetCursorInfo() If IsArray($aInfo) Then If $aInfo[3] = 1 And $aInfo[4] = $ebRegExp Then ; right click ($aInfo[3] = 1) while hovering over Edit Control in TabSheet0 $mPos = MouseGetPos() _TrackPopupMenu($hGUI, $hDummycontext, $mPos[0], $mPos[1]) EndIf EndIf $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE, $btnClose ; =========== ; 10/02/2024 : first, check length (in bytes) of what will become StringToBinary(GUICtrlRead($ebPersonal), 4)) during IniWrite() ; If > 65.534 (e.g. if > 65.536 after @crlf will be automatically appended) then IniRead() will be a problem when script re-run ; because the max. length of a value (of a key in a section of an ini file) is 64Kb (e.g. 64 * 1024 = 65.536 bytes) : tested. ; Note that "0x" at the beginning of the binary string is included in the 65.534 limit, it's the @crlf (2 bytes) that's not. ; ; Though an ini file can have ANY maximum size (with a maximum of 64Kb for any value in it), a function like IniReadSection() ; is limited to ini files having a TOTAL length of 32Kb ("for legacy reason") AutoIt help file, topic IniReadSection() : tested. ; Maybe other related functions like IniReadSectionNames() or even IniWriteSection() have the same 32Kb limitation (?) ; ; Anyway, when using only IniWrite() and IniRead() like in this script, then we can reach the max. of 64Kb for any value (+++) ; with an ini file having any maximum size : remember to never use IniReadSection() and its 32Kb limitation in this case ! ; For the record, I never used IniReadSection() or IniReadSectionNames() or IniWriteSection() so there shouldn't be a problem. Local $dBin = StringToBinary(GUICtrlRead($ebPersonal), 4) ; 4 = $SB_UTF8 (string data is UTF8) If StringLen($dBin) > 65534 Then ; we use StringLen() and not BinaryLen() which would of course be much smaller because ; each character is coded on 2 bytes (mostly) or 4 bytes (for some special chars in UTF8) ; which in fact limits the binary 'Personal' Tab to half (at least) of 64Kb ; But hey, 32Kb (a bit less) of characters should be enough for the 'Personal' Tab ; Remember we used binary because EOL and some other characters aren't accepted inside values ; of ini files (see important notes in AutoIt help file, topic IniWrite) MsgBox($MB_TOPMOST, "Size of 'Personal' Tab is too big", _ "Its size is " & StringLen($dBin) & " bytes (plus @crlf) which exceeds the 64Kb limit." & @crlf & _ "This would corrupt the ini file which will not be readable later." & @crlf & _ @crlf & _ "Please remove lines from the 'Personal' Tab, do a manual copy of it etc..." & @crlf & _ "This script will not close unless the 'Personal' Tab got a size <= 64 Kb") ContinueLoop ; While 1 EndIf ; =========== IniWrite($sIniFile, "Main", "Mode", $nMode) IniWrite($sIniFile, "Main", "LineNum", GUICtrlRead($cbLineNum)) IniWrite($sIniFile, "Main", "ReplaceCount", Int(GUICtrlRead($ibRepCount))) IniWrite($sIniFile, "Main", "Pattern", StringToBinary(GUICtrlRead($ebRegExp), 4)) ; 4 = $SB_UTF8 (string data is UTF8) IniWrite($sIniFile, "Main", "Replace", StringToBinary(GUICtrlRead($ebRegExpReplace), 4)) IniWrite($sIniFile, "Main", "Prefix", StringToBinary(GUICtrlRead($ebResultPrefix), 4)) IniWrite($sIniFile, "Main", "Suffix", StringToBinary(GUICtrlRead($ebResultSuffix), 4)) ; IniWrite($sIniFile, "Main", "Personal", StringToBinary(GUICtrlRead($ebPersonal), 4)) ; 10/02/2024 : next line does same, ... IniWrite($sIniFile, "Main", "Personal", $dBin) ; ...as length test was added immediately after Case $GUI_EVENT_CLOSE, $btnClose Local $hTxtFile = FileOpen($sTxtFile, 2) ; 2 = Write mode (erase previous contents) FileWrite($hTxtFile, GUICtrlRead($ebTest)) FileClose($hTxtFile) DllClose($hDll) ; close user32.dll (was opened so DllCall's in _TrackPopupMenu() didn't open/close it at each call) GUIDelete($hGUI) Exit Case $idMenu_Start To $idMenu_End $sMenuData = GUICtrlRead($nMsg, 1) GUICtrlSendMsg($ebRegExp, 0x00C2, 1, StringLeft($sMenuData, StringInStr($sMenuData, @TAB)-1)) ; 0x00C2 = $EM_REPLACESEL ; 1 (or True) = allow Undo ; GUICtrlSetState($ebRegExp, $GUI_FOCUS) ; better caret position when line commented out. Case $cbMode $nMode = GUICtrlSendMsg($cbMode, $CB_GETCURSEL, 0, 0) Case $btnCode GUICtrlSetState($btnCode, $GUI_DISABLE) ; prevent accidental double click on the button _GenerateCode() ; generate AutoIt code and copy it to Clipboard GUICtrlSetState($btnCode, $GUI_ENABLE) Case $btnClear If MsgBox(BitOr($MB_YESNO, $MB_TOPMOST, $MB_ICONQUESTION, $MB_DEFBUTTON2), _ "Attention", "Clear all fields ?", 0, $hGUI) = $IDYES Then GUICtrlSetData($ebTest, "") GUICtrlSetData($ebRegExp, "") GUICtrlSetData($ebRegExpReplace, "") GUICtrlSetData($ebResultPrefix, "") GUICtrlSetData($ebResultSuffix, "") ; never clear the 'Personal' Tab here EndIf Case $GUI_EVENT_DROPPED If @GUI_DragId = -1 Then ; -1 means dragged from a file (only alternative is to drag from... Listview item : help file) GUICtrlSetData(@GUI_DropId, FileRead(@GUI_DragFile)) EndIf EndSwitch Check_Highlight() ; check 3 TabItems content (empty or not), then possibly turn on / off their highlight If $_g_bWasAChange Or ($nMsg <> 0 And $nMsg <> -11) Then ; mLipok for $_g_bWasAChange . $GUI_EVENT_MOUSEMOVE = -11 (me) RegExpExecute() $_g_bWasAChange = False EndIf WEnd ;================================================================= Func RegExpExecute() Local $vResult, $vTemp, $sResult = "Failed", $sCount = "", $error, $nCurColor Local $sResultPrefix = GUICtrlRead($ebResultPrefix), $sResultSuffix = GUICtrlRead($ebResultSuffix), _ $bShowGroupsNumber = (GUICtrlRead($cbLineNum) = $GUI_CHECKED) If GUICtrlRead($ebRegExpReplace) <> "" Then ; if Edit control "Replace Pattern" isn't empty => StringRegExpReplace If Not BitAND(GUICtrlGetState($cbMode), $GUI_DISABLE) Then GUICtrlSetState($cbMode, $GUI_DISABLE) If Not BitAND(GUICtrlGetState($ibRepCount), $GUI_ENABLE) Then GUICtrlSetState($ibRepCount, $GUI_ENABLE) If Not BitAND(GUICtrlGetState($cbLineNum), $GUI_DISABLE) Then GUICtrlSetState($cbLineNum, $GUI_DISABLE) ; added that one $sResult = $sResultPrefix & _ StringRegExpReplace(GUICtrlRead($ebTest), GUICtrlRead($ebRegExp), GUICtrlRead($ebRegExpReplace), GUICtrlRead($ibRepCount)) & _ $sResultSuffix $sCount = "Groups replaced: " & @extended & " (result length: " & StringLen($sResult) & ")" Else ; Edit control "Replace Pattern" is empty, so we're dealing now with "Search Pattern" Edit control => StringRegExp If Not BitAND(GUICtrlGetState($cbMode), $GUI_ENABLE) Then GUICtrlSetState($cbMode, $GUI_ENABLE) If Int(GUICtrlRead($ibRepCount)) <> 0 Then GUICtrlSetData($ibRepCount, 0) ; added that one If Not BitAND(GUICtrlGetState($ibRepCount), $GUI_DISABLE) Then GUICtrlSetState($ibRepCount, $GUI_DISABLE) If Not BitAND(GUICtrlGetState($cbLineNum), $GUI_ENABLE) Then GUICtrlSetState($cbLineNum, $GUI_ENABLE) ; added that one $nCurColor = 0 ; black $vResult = StringRegExp(GUICtrlRead($ebTest), GUICtrlRead($ebRegExp), $nMode) $error = @error $extended = @extended ; Workaround about editbox flickering If $error = 2 Then $nCurColor = 0xFF0000 ; red . $error = 2 means bad pattern (in any mode) If $nColor <> $nCurColor Then GUICtrlSetColor($ebRegExp, $nCurColor) $nColor = $nCurColor If $nMode = 0 Then If $vResult Then $sResult = "Matched" Else ; Mode 1/2/3/4 If Not $error Then $sResult = "" $vTemp = 0 If $nMode = 4 Then $sCount = "Global matches: " & UBound($vResult) For $i = 0 to UBound($vResult) - 1 If $i > 0 Then $sResult &= @CRLF ; version 2.5e : prevent here (& below) an annoying @CRLF at the end of the Result field $vTemp = $vResult[$i] $sResult &= "--- Global match " & $i+1 & " ---" & @CRLF For $j = 0 To UBound($vTemp) - 1 If $j > 0 Then $sResult &= @CRLF If $bShowGroupsNumber Then $sResult &= StringFormat("%0" & StringLen(String(UBound($vTemp))) & "d: %s", $j, $sResultPrefix & $vTemp[$j] & $sResultSuffix) Else $sResult &= $sResultPrefix & $vTemp[$j] & $sResultSuffix EndIf Next Next If IsArray($vTemp) Then $sCount = "Groups matched: " & UBound($vTemp) & " (global matches: " & UBound($vResult) & ")" Else ; Mode 1/2/3 $sCount = "Groups matched: " & UBound($vResult) & ($nMode < 3 ? (" (next offset: " & $extended & ")") : "") For $i = 0 to UBound($vResult) - 1 If $i > 0 Then $sResult &= @CRLF If $bShowGroupsNumber Then $sResult &= StringFormat("%0" & StringLen(String(UBound($vResult))) & "d: %s", $i, $sResultPrefix & $vResult[$i] & $sResultSuffix) Else $sResult &= $sResultPrefix & $vResult[$i] & $sResultSuffix EndIf Next EndIf EndIf EndIf EndIf If $sOldResult <> $sResult Or $sOldCount <> $sCount Then GUICtrlSetData($ebResult, $sResult) GUICtrlSetData($lblCount, $sCount) EndIf $sOldResult = $sResult $sOldCount = $sCount ; Wow... w0uter's workaround is still actual... ; Don't know, not recall what the prob was... ; StringRegExp('', Random(0x80000000, 0x7FFFFFFF), 1) EndFunc ;==>RegExpExecute ;================================================================= Func _TrackPopupMenu($hWnd, $hMenu, $x, $y) DllCall($hDll, "int", "TrackPopupMenuEx", "hwnd", $hMenu, "int", 0, "int", $x, "int", $y, "hwnd", $hWnd, "ptr", 0) EndFunc ;==>_TrackPopupMenu ;================================================================= Func Check_Highlight() For $i = 0 To 2 ; 3 TabItems to check If GUICtrlRead($Tab_Highlight[$i][0]) = "" Then ; if Edit control is empty in this TabItem... If $Tab_Highlight[$i][1] Then ; ...and if it's highlited... GUICtrlSendMsg($tabExpr, $TCM_HIGHLIGHTITEM, $i + 1, False) ; ...then don't highlight this TabItem $Tab_Highlight[$i][1] = False EndIf Else ; Edit control not empty in this TabItem... If Not $Tab_Highlight[$i][1] Then ; ...and if it's not highlited... GUICtrlSendMsg($tabExpr, $TCM_HIGHLIGHTITEM, $i + 1, True) ; ...then highlight this TabItem $Tab_Highlight[$i][1] = True EndIf EndIf Next EndFunc ;==>Check_Highlight ;================================================================= Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam) ; mLipok, reworked ; Local $hWndFrom = $lParam ; Local $iIDFrom = _WinAPI_LoWord($wParam) Local $iIDFrom = BitAND($wParam, 0xFFFF) ; same (cf WinAPIConv.au3) ; Local $iCode = _WinAPI_HiWord($wParam) Local $iCode = BitShift($wParam, 16) ; same (cf WinAPIConv.au3) Switch $iIDFrom Case $ebTest, $ebRegExp, $ebRegExpReplace, $ebResultPrefix, $ebResultSuffix, $ibRepCount Switch $iCode Case $EN_CHANGE ; Sent when the user has taken an action that may have altered text in an edit control (mLipok) $_g_bWasAChange = True If Not GUICtrlRead($ibRepCount) Then GUICtrlSetData($ibRepCount, 0) ; in case empty field => force 0 EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_COMMAND ;================================================================= Func WM_GETMINMAXINFO($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam If $hWnd = $hGUI Then Local $minmaxinfo = DllStructCreate("int;int;int;int;int;int;int;int;int;int", $lParam) DllStructSetData($minmaxinfo, 7, $aGUIInitPos[2]) ; min width DllStructSetData($minmaxinfo, 8, $aGUIInitPos[3] / 1.5) ; min height, testing / 1.5 seems ok Return 0 ; "If an application processes this message, it should return zero." (msdn) EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_GETMINMAXINFO ;================================================================= Func _GenerateCode() Local $sClipTxt, $sSubject, $sPattern $sSubject = _TextSplit(GUICtrlRead($ebTest), "$sSubject") ; 2nd param. used literally in generated code $sPattern = _TextSplit(GUICtrlRead($ebRegExp), "$sPattern") ; ditto If $sSubject = "" Or $sPattern = "" Then MsgBox(0, "Generating code", "error : Match Text OR Search Pattern are empty", 0, $hGUI) Return EndIf If Not GUICtrlRead($ebRegExpReplace) Then ; generate StringRegExp code If $nMode > 0 Then ; 1/2/3/4 $sClipTxt = "#include " & @crlf & @crlf & _ "Local $sSubject, $sPattern, $nMode, $aArray" & @crlf & @crlf & _ "$sSubject = " & $sSubject & @crlf & @crlf & _ "$sPattern = " & $sPattern & @crlf & @crlf & _ "$nMode = " & $nMode & @crlf & @crlf & _ "$aArray = StringRegExp($sSubject, $sPattern, $nMode)" & @crlf & @crlf & _ "If Not @error Then" & @crlf & _ " Switch $nMode" & @crlf & _ " Case 1 To 3" & @crlf & _ " _ArrayDisplay($aArray, '_ArrayDisplay mode ' & $nMode)" & @crlf & _ " Case 4" & @crlf & _ " _ArrayDisplay($aArray, 'Array of arrays')" & @crlf & _ " _ViewSubArrays($aArray)" & @crlf & _ " EndSwitch" & @crlf & _ "Else" & @crlf & _ " MsgBox(0, 'StringRegExp', 'error = ' & @error & (@error = 1 ? ' (no matches)' : ' (bad pattern)'))" & @crlf & _ "EndIf" & @crlf & _ @crlf & _ "Func _ViewSubArrays(Const ByRef $aArray)" & @crlf & _ " Local $aArray2[Ubound($aArray)][100], $iNbCol, $iMaxCol" & @crlf & _ " SplashTextOn('', 'Preparing 2D array' & @crlf & 'please wait...', 250, 50, -1, -1, 1 + 32)" & @crlf & _ " For $i = 0 To Ubound($aArray) - 1" & @crlf & _ " $iNbCol = Ubound($aArray[$i]) ; 1 internal 1D sub-array will become 1 row in a 2D array" & @crlf & _ " If $iNbCol > $iMaxCol Then $iMaxCol = $iNbCol" & @crlf & _ " $aArray2[$i][0] = ( StringLen(($aArray[$i])[0]) < 61 ) _ ; column 0 always exists (global match)" & @crlf & _ " ? ($aArray[$i])[0] _" & @crlf & _ " : ( StringLeft(($aArray[$i])[0], 30) & ' ... ' & StringRight(($aArray[$i])[0], 30) )" & @crlf & _ " For $j = 1 To $iNbCol - 1" & @crlf & _ " $aArray2[$i][$j] = ($aArray[$i])[$j]" & @crlf & _ " Next" & @crlf & _ " Next" & @crlf & _ " Redim $aArray2[Ubound($aArray)][$iMaxCol]" & @crlf & _ " SplashOff()" & @crlf & _ " _ArrayDisplay($aArray2, 'Internal sub-arrays', Default, Default, Default, 'Global match')" & @crlf & _ "EndFunc ;==>_ViewSubArrays" & @crlf Else ; mode 0 doesn't generate an Array but an Int32 $sClipTxt = "Local $sSubject, $sPattern, $nMode, $iMatch" & @crlf & @crlf & _ "$sSubject = " & $sSubject & @crlf & @crlf & _ "$sPattern = " & $sPattern & @crlf & @crlf & _ "$nMode = " & $nMode & @crlf & @crlf & _ "$iMatch = StringRegExp($sSubject, $sPattern, $nMode)" & @crlf & @crlf & _ "MsgBox(0, 'Matched ?', ($iMatch ? 'yes' : 'no'))" & @crlf EndIf Else ; generate StringRegExpReplace code Local $sReplace, $iCount $sReplace = _TextSplit(GUICtrlRead($ebRegExpReplace), "$sReplace") ; 2nd param. used literally in generated code $iCount = Int(GUICtrlRead($ibRepCount)) $sClipTxt = "Local $sSubject, $sPattern, $sReplace, $iCount, $sOutput" & @crlf & @crlf & _ "$sSubject = " & $sSubject & @crlf & @crlf & _ "$sPattern = " & $sPattern & @crlf & @crlf & _ "$sReplace = " & $sReplace & @crlf & @crlf & _ "$iCount = " & $iCount & (($iCount = 0) ? " ; 0 means global replacement" : "") & @crlf & @crlf & _ "$sOutput = StringRegExpReplace($sSubject, $sPattern, $sReplace, $iCount)" & @crlf & @crlf & _ "MsgBox(0, 'StringRegExpReplace', $sOutput)" & @crlf EndIf ClipPut($sClipTxt) MsgBox(0, "Code (copied to Clipboard)", ClipGet(), 0, $hGUI) EndFunc ;==>_GenerateCode ;================================================================= Func _TextSplit($sString, $sCaller) Local $iMaxLineSize = 2000 ; changeable but tested ok . Though Scite MaxLine length = 4095, just think of ... ; ...possible plenty newline chars or ' expanded below, not forgetting possible @Tab characters expanded in Scite Local $iStringSize = StringLen($sString) ; ConsoleWrite("[" & $sCaller & "] " & "Initial $iStringSize = " & $iStringSize & @crlf & @crlf) Local $sLi = "", $iLiSize = 0, $b5CharsFound = False, $sRet = "" While $iStringSize > 0 $sLi = StringLeft($sString, $iMaxLineSize) $iLiSize = StringLen($sLi) ; important variable declared here, as $sLi is gonna be altered below. ; ConsoleWrite("[" & $sCaller & "] " & "$iLiSize = " & $iLiSize & @crlf) $sLi = "'" & StringReplace($sLi, "'", "''") & "'" ; surround with ' (by design) and double all eventual ' inside StringRegExp($sLi, '\R', 1) ; check 1st EOL match (if any) . EOL can be @crlf or @lf or @cr If Not @error Then ; EOL found in $sLi StringRegExp($sLi, "& '' ", 1) ; as there is (at least) 1 EOL in $sLi, check if these 5 problematic chars are found in $sLi $b5CharsFound = Not @error ? True : False ; if they're found => we'll keep them in $sLi after the 3 StringReplace() below $sLi = StringReplace($sLi, @crlf, "' & @crlf & '") ; @crlf first $sLi = StringReplace($sLi, @lf, "' & @lf & '") $sLi = StringReplace($sLi, @cr, "' & @cr & '") ; 3 following If's are useful, as they generate a simplified code If StringLeft($sLi, 5) = "'' & " Then $sLi = StringTrimLeft($sLi, 5) ; safe to execute this line (impossible '' in original) If StringRight($sLi, 5) = " & ''" Then $sLi = StringTrimRight($sLi, 5) ; ditto If Not $b5CharsFound Then ; If 5 original chars were not part of $sLi before the 3 StringReplace() above, then... $sLi = StringReplace($sLi, "& '' ", "") ; ...they may be part of $sLi now, in case several followed newlines at middle of $sLi were treated EndIf EndIf ; ConsoleWrite("[" & $sCaller & "] " & "Len $sLi altered = " & StringLen($sLi) & @crlf) ; ConsoleWrite("[" & $sCaller & "] " & "$sLi altered = " & $sLi & @crlf) If $sRet = "" Then ; 1st passage $sRet = $sLi Else $sRet &= @crlf & " " & $sCaller & " &= " & $sLi EndIf $sString = StringMid($sString, $iLiSize + 1) $iStringSize = StringLen($sString) ; ConsoleWrite("[" & $sCaller & "] " & "Remaining $iStringSize = " & $iStringSize & @crlf & @crlf) WEnd Return $sRet EndFunc ;==>_TextSplit ;================================================================= Func _PrepareContextMenu() ; Group here all GUICtrlCreateMenu() so their id's will precede all the Context menus lines id's defined by GUICtrlCreateMenuItem(...) below Local $mnu100 = GUICtrlCreateMenu("Options", $lblDummycontext) Local $mnu200 = GUICtrlCreateMenu("Anchors && Assertions", $lblDummycontext) Local $mnu300 = GUICtrlCreateMenu("Matching Characters", $lblDummycontext) Local $mnu400 = GUICtrlCreateMenu("Character Classes && Posix", $lblDummycontext) Local $mnu500 = GUICtrlCreateMenu("Groups && Backreferences", $lblDummycontext) Local $mnu600 = GUICtrlCreateMenu("Repeating Characters", $lblDummycontext) ; All Context menus items id's are defined in a single interval : from $idMenu_Start to $idMenu_End ; It will allow a simple test later, during the GUI loop : Case $idMenu_Start To $idMenu_End $idMenu_Start = GUICtrlCreateMenuItem("(?i)"&@TAB&"case-insensitive", $mnu100) GUICtrlCreateMenuItem("(?m)"&@TAB&"^ and $ match at newlines chars within data", $mnu100) GUICtrlCreateMenuItem("(?s)"&@TAB&". matches anything, including newline chars", $mnu100) GUICtrlCreateMenuItem("(?U)"&@TAB&"Ungreedy (quantifiers become lazy)", $mnu100) GUICtrlCreateMenuItem("(?x)"&@TAB&"ignore whitespace chars and # comments", $mnu100) GUICtrlCreateMenuItem("(?Usi)"&@TAB&"ex: Ungreedy, dotall, case-insensitive", $mnu100) GUICtrlCreateMenuItem("", $mnu100) GUICtrlCreateMenuItem("(?- )"&@TAB&"unset option(s) ex. (?-im) etc...", $mnu100) GUICtrlCreateMenuItem("^"&@TAB&"beginning of string, or after a newline if (?m)", $mnu200) GUICtrlCreateMenuItem("\A"&@TAB&"beginning of string, no matter (?m)", $mnu200) GUICtrlCreateMenuItem("\G"&@TAB&"beginning of string, or end of the previous match", $mnu200) GUICtrlCreateMenuItem("$"&@TAB&"end of string, or before a newline if (?m)", $mnu200) GUICtrlCreateMenuItem("\z"&@TAB&"end of string, no matter (?m)", $mnu200) GUICtrlCreateMenuItem("\Z"&@TAB&"end of string, or b4 newline at the end, no matter (?m)", $mnu200) GUICtrlCreateMenuItem("", $mnu200) GUICtrlCreateMenuItem("\b"&@TAB&"match at a word boundary", $mnu200) GUICtrlCreateMenuItem("\B"&@TAB&"match when not at a word boundary", $mnu200) GUICtrlCreateMenuItem("\K"&@TAB&"reset start of match at the current position", $mnu200) GUICtrlCreateMenuItem("(?= )"&@TAB&"positive lookahead q(?=u) q followed by u", $mnu200) GUICtrlCreateMenuItem("(?! )"&@TAB&"negative lookahead q(?!u) q not followed by u", $mnu200) GUICtrlCreateMenuItem("(?<= )"&@TAB&"positive lookbehind (?<=u)q q preceded by u", $mnu200) GUICtrlCreateMenuItem("(??@[\]^_`{|}~", $mnu400) GUICtrlCreateMenuItem("[:space:]"&@TAB&"whitespace, chr(9) to chr(13) and chr(32)", $mnu400) GUICtrlCreateMenuItem("[:upper:]"&@TAB&"uppercase letters, [A-Z]", $mnu400) GUICtrlCreateMenuItem("[:word:]"&@TAB&"word characters, \w or [[:alnum:]_]", $mnu400) GUICtrlCreateMenuItem("[:xdigit:]"&@TAB&"hexadecimal digits, [0-9A-Fa-f]", $mnu400) GUICtrlCreateMenuItem("", $mnu400) GUICtrlCreateMenuItem("[:^xdigit:]"&@TAB&"non-hexadecimal digits, [^0-9A-Fa-f] etc...", $mnu400) GUICtrlCreateMenuItem("( )"&@TAB&"capturing group", $mnu500) GUICtrlCreateMenuItem("(?: )"&@TAB&"non-capturing group", $mnu500) GUICtrlCreateMenuItem("(?| )"&@TAB&"non-capturing group with reset", $mnu500) GUICtrlCreateMenuItem("(?> )"&@TAB&"atomic non-capturing group (no backtrack)", $mnu500) GUICtrlCreateMenuItem("(?# )"&@TAB&"comment group (not nestable)", $mnu500) GUICtrlCreateMenuItem("(? )"&@TAB&"named capturing group ex. (?[A-Z]+)", $mnu500) GUICtrlCreateMenuItem("", $mnu500) GUICtrlCreateMenuItem(""&@TAB&"Backreferences of previously captured groups", $mnu500) GUICtrlCreateMenuItem("\n"&@TAB&"absolute group number ex: \1 to \9", $mnu500) GUICtrlCreateMenuItem("\gn"&@TAB&"absolute group number (safer) ex: \g1", $mnu500) GUICtrlCreateMenuItem("\g{n}"&@TAB&"absolute group number (safest) ex: \g{1}", $mnu500) GUICtrlCreateMenuItem("\g{-n}"&@TAB&"relative group number ex: \g{-1}", $mnu500) GUICtrlCreateMenuItem("\k"&@TAB&"named group ex: \k", $mnu500) GUICtrlCreateMenuItem(""&@TAB&"Repeat the previous character, class, group or backreference", $mnu600) GUICtrlCreateMenuItem("*"&@TAB&"0 or more times", $mnu600) GUICtrlCreateMenuItem("+"&@TAB&"1 or more times", $mnu600) GUICtrlCreateMenuItem("?"&@TAB&"0 or 1 time", $mnu600) GUICtrlCreateMenuItem("{x}"&@TAB&"exactly x times", $mnu600) GUICtrlCreateMenuItem("{x,}"&@TAB&"at least x times", $mnu600) GUICtrlCreateMenuItem("{,x}"&@TAB&"at most x times", $mnu600) GUICtrlCreateMenuItem("{x,y}"&@TAB&"between x and y times", $mnu600) GUICtrlCreateMenuItem("", $mnu600) GUICtrlCreateMenuItem("?"&@TAB&"(after any of the above) find the smallest match (Ungreedy)", $mnu600) $idMenu_End = GUICtrlCreateMenuItem("+"&@TAB&"(after any of the above) possessive (e.g. atomic and greedy)", $mnu600) EndFunc ;==>_PrepareContextMenu