Sign in to follow this  
Followers 0
Mat

StringRegExpReplaceCallback

9 posts in this topic

So I decided I needed this, and wrote a nice workaround. Usage is simple:

#include "StringRegExpReplaceCallback.au3"

$sString = "%48%65%6C%6C%6F%2C%20%77%6F%72%6C%64%21"
MsgBox(0, $sString, StringRegExpReplaceCallback($sString, "%([0-9A-f]{2})", "Callback"))

Func Callback($asMatches)
    Return Chr(Dec($asMatches[1]))
EndFunc   ;==>Callback

How it works

It uses StringRegExp with the second option, and passes that array straight to the callback function. It then replaces the match with the return value of the callback by using StringLeft() & StringRight() so that that will be the only replacement made and will be accurate. It then increments the offset so that the same match won't be returned in the next loop.

The callback function is passed the array, and returns the replacement value. If it sets the @error flag to non-zero then the function will stop looping.

; #FUNCTION# =====================================================================================================================
; Name...........: StringRegExpReplaceCallback
; Description ...:
; Syntax.........: StringRegExpReplaceCallback($sString, $sPattern, $sFunc [, $iLimit ] )
; Parameters ....: $sString       - The input string.
;                  $sPattern      - The regular expression to compare. See StringRegExp for pattern definition characters.
;                  $sFunc         - The name of the user function to call.
;                  $iLimit        - [Optional] The max number of time to call the callback function. Default (zero) is unlimited.
; Return values .: Success        - The new string. The number of callbacks done.
;                  Failure        - Will return the original string and set the @error flag.
; Author ........: Mat
; Modified.......:
; Remarks .......: The callback function should have a single argument. This will be an array of matches, with the complete match
;                  in the first element.
; Related .......:
; Link ..........: http://www.php.net/manual/en/function.preg-replace-callback.php
; Example .......: Yes
; ================================================================================================================================
Func StringRegExpReplaceCallback($sString, $sPattern, $sFunc, $iLimit = 0)
    Local $iOffset = 1, $iDone = 0, $iMatchOffset

    While True
        $aRes = StringRegExp($sString, $sPattern, 2, $iOffset)
        If @error Then ExitLoop

        $sRet = Call($sFunc, $aRes)
        If @error Then Return SetError(@error, $iDone, $sString)

        $iOffset = StringInStr($sString, $aRes[0], 1, 1, $iOffset)
        $sString = StringLeft($sString, $iOffset - 1) & $sRet & StringMid($sString, $iOffset + StringLen($aRes[0]))
        $iOffset += StringLen($sRet)

        $iDone += 1
        If $iDone = $iLimit Then ExitLoop
    WEnd

    Return SetExtended($iDone, $sString)
EndFunc   ;==>StringRegExpReplaceCallback

Download Link

Downloads so far is shown on the downloads page.

Mat

Share this post


Link to post
Share on other sites



http://www.autoitscript.com/trac/autoit/ticket/588

http://www.autoitscript.com/forum/index.php?showtopic=82292


 

Spoiler

Using OS: Win 7 Professional, Using AutoIt Ver(s): 3.3.6.1 / 3.3.8.1

AutoIt_Rus_Community.png AutoIt Russian Community

My Work...

Spoiler

AutoIt_Icon_small.pngProjects: ATT - Application Translate Tool {new}| BlockIt - Block files & folders {new}| SIP - Selected Image Preview {new}| SISCABMAN - SciTE Abbreviations Manager {new}| AutoIt Path Switcher | AutoIt Menu for Opera! | YouTube Download Center! | Desktop Icons Restorator | Math Tasks | KeyBoard & Mouse Cleaner | CaptureIt - Capture Images Utility | CheckFileSize Program

AutoIt_Icon_small.pngUDFs: OnAutoItErrorRegister - Handle AutoIt critical errors {new}| AutoIt Syntax Highlight {new}| Opera Library! | Winamp Library | GetFolderToMenu | Custom_InputBox()! | _FileRun UDF | _CheckInput() UDF | _GUIInputSetOnlyNumbers() UDF | _FileGetValidName() UDF | _GUICtrlCreateRadioCBox UDF | _GuiCreateGrid() | _PathSplitByRegExp() | _GUICtrlListView_MoveItems - UDF | GUICtrlSetOnHover_UDF! | _ControlTab UDF! | _MouseSetOnEvent() UDF! | _ProcessListEx - UDF | GUICtrl_SetResizing - UDF! | Mod. for _IniString UDFs | _StringStripChars UDF | _ColorIsDarkShade UDF | _ColorConvertValue UDF | _GUICtrlTab_CoverBackground | CUI_App_UDF | _IncludeScripts UDF | _AutoIt3ExecuteCode | _DragList UDF | Mod. for _ListView_Progress | _ListView_SysLink | _GenerateRandomNumbers | _BlockInputEx | _IsPressedEx | OnAutoItExit Handler | _GUICtrlCreateTFLabel UDF | WinControlSetEvent UDF | Mod. for _DirGetSizeEx UDF
 
AutoIt_Icon_small.pngExamples: 
ScreenSaver Demo - Matrix included | Gui Drag Without pause the script | _WinAttach()! | Turn Off/On Monitor | ComboBox Handler Example | Mod. for "Thinking Box" | Cool "About" Box | TasksBar Imitation Demo

Like the Projects/UDFs/Examples? Please rate the topic (up-right corner of the post header: Rating AutoIt_Rating.gif)

* === My topics === *

==================================================
My_Userbar.gif
==================================================

 

 

 

AutoIt is simple, subtle, elegant. © AutoIt Team

Share this post


Link to post
Share on other sites

http://www.autoitscript.com/trac/autoit/ticket/588

http://www.autoitscript.com/forum/index.php?showtopic=82292

Thats an interesting way to go about it. It took me a while to understand how it worked. Same principle and based on the php one as well. There I was thinking I was being original ;)

I'm guessing this isn't due for inclusion as an AutoIt built in function anytime soon then if it's been a ticket longer than I've on the forums :)

Share this post


Link to post
Share on other sites

$asdf = 'aaa bbb cc"c ddd eee'
$as = StringRegExpReplaceCallback($asdf , "aaa|bbb|ccc" , "upper")
MsgBox(0 ,"Callback?", $as)

Func StringRegExpReplaceCallback($string , $pattern , $callback)
    Return StringReplace(Execute('"' & StringRegExpReplace(StringReplace($string , '"' , "\x22") , $pattern , StringFormat('" & %s("\0") & "' , $callback)) & '"') , "\x22" , '"')
EndFunc


Func upper($text)
    Return StringUpper($text)
EndFunc

This works just fine for my scripts ;)


Only two things are infinite, the universe and human stupidity, and i'm not sure about the former -Alber EinsteinPractice makes perfect! but nobody's perfect so why practice at all?http://forum.ambrozie.ro

Share this post


Link to post
Share on other sites

I like that one. However I'd use a non-printable character instead of "\x22". Something like

StringReplace($string , '"' , Chr(26))

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

Hmm, your original version fails if the string and search pattern have double quotes in them, and you want to search for or manipulate the quote characters. That happens because they are being replaced before making it to the callback function. I've come up with a solution that requires an intermediate function to handle it.

Func StringRegExpReplaceCallback($sString , $sPattern , $sCallback)
    ; replace quotes in pattern and string with Chr(26) (non-printing ASCII character) before running the SRERep
    ; then change back any remaining Chr(26)'s to quotes before returning the final string
    Return StringReplace(Execute('"' & StringRegExpReplace(StringReplace($sString, '"', Chr(26)), StringReplace($sPattern, '"', Chr(26)), StringFormat('" & _intSRECallback("${0}", "%s") & "', $sCallback)) & '"'), Chr(26), '"')
EndFunc

Func _intSRECallback($sString, $sCallback)
    ; intermediate callback: replace Chr(26) in matches with quotes again so the user callback has unaltered text to work with
    ; this all happens during the Execute() statement, so we don't need to change remaining quotes back to Chr(26) before returning
    Return Call($sCallback, StringReplace($sString, Chr(26), '"'))
EndFunc

Func _callback($s)
    Return StringUpper($s)
EndFunc

Func _callback2($s)
    Return StringReplace($s, '"', "Z")
EndFunc

ConsoleWrite(StringRegExpReplaceCallback('aa"a bbb cc"c ddd', 'cc"c', "_callback") & @CRLF)
ConsoleWrite(StringRegExpReplaceCallback('aa"a bbb cc"c ddd', 'cc"c', "_callback2") & @CRLF)

I have no idea how well this works in terms of performance versus some of the other solutions. It may be very one-liner ish, but looks like it could be pretty slow.

Edited by wraithdu

Share this post


Link to post
Share on other sites

Theres a reason I did it properly the first time I think :P

What if I want to use character 26 in my string? :) You now want a small line to find a character not used in the string... or in the regex pattern... and that includes using matching characters ;) Why not just write your own regex library? ;)

Share this post


Link to post
Share on other sites

Well if you or I want to use Chr(26) in a string for some crazy reason, then we have to go back and rewrite Au3Int as well.

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

Well if you or I want to use Chr(26) in a string for some crazy reason, then we have to go back and rewrite Au3Int as well.

I had a funny feeling that would be the reply. I even remember why I chose chr(26)... When I looked at an ascii table they called the character "SUB (substitute)", so I figured that this is exactly what it was for ;)

Chr(26) is the "CTRL-Z" code of ASCII/ISO646 keyboards

Not sure if that means that Chr(26) actually has a use... :)

I could (in theory) do it with Au3Int, but it would be a big bit of work... I reckon it's a case of writing a new function called _Au3Int_CommaSplit that splits on valid commas (without character changing) rather than replacing invalid ones. That is ultimately what the function does (eventually). That would work. The only problem is I'm getting lost just trying to find where we use the comma strip routine :P

To prove a point I'm going to do it (if I can).

Edit: I think we were being a bit stupid not to do this in the first place ;) (Line 77+)

_Au3Int_CommaStrip($sLine)
    $asParams = StringSplit($sLine, ",")

    ; Undo the comma strips:
    For $i = 1 To $asParams[0]
        $asParams[$i] = StringReplace($asParams[$i], Chr(26), ",")
    Next
Edited by Mat

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0