Jump to content
Sign in to follow this  
Mat

Extra string funtions

Recommended Posts

Mat

A few new functions that are very useful, and very simple if you know your RegEx. Most of these i've accumulated over the weeks from questions in h+s, and other projects I've been doing. These are also pretty good examples of how to use RegExp, particularly the \Q and \E tags which I feel are seriously under used. The other thing that should be used more are the {} tags for repetition a fixed amount of times, they've been used in there too.

Func _StringInStrCount ($sString, $sFind, $bCaseSense = False)
   Local $sCase = "(?i)"
   If $bCaseSense = True Then $sCase = ""
   Return UBound (StringRegExp ($sString, $sCase & "(\Q" & $sFind & "\E)", 3))
EndFunc ; ==> _StringInStrCount

Func _StringSplitByLine ($sString, $bCountBlank = False)
   Local $sChar = "+"
   If $bCountBlank = True Then $sChar = "*"
   Return StringRegExp ($sString, "(." & $sChar & ")(?:\n)?", 3)
EndFunc ; ==> _StringSplitByLine

Func _StringAddLine ($sString, $iLine, $sLine, $bCountBlank = False)
   Local $sChar = "+"
   If $bCountBlank = True Then $sChar = "*"
   If Not IsInt ($iLine) Then Return SetError (1, 0, "")
   Return StringRegExpReplace ($sString, "((." & $sChar & "(\n)){" & $iLine & "})(?s)(." & $sChar & ")", "\1" & $sLine & "\3\4")
EndFunc ; ==> _StringAddLine

Func _StringGetLine ($sString, $iLine, $bCountBlank = False)
   Local $sChar = "+"
   If $bCountBlank = True Then $sChar = "*"
   If Not IsInt ($iLine) Then Return SetError (1, 0, "")
   Return StringRegExpReplace ($sString, "((." & $sChar & "\n){" & $iLine & "})(." & $sChar & "\n)((." & $sChar & "\n?)+)", "\2")
EndFunc ; ==> _StringGetLine

Func _StringRemoveLine ($sString, $iLine, $bCountBlank = False)
   Local $sChar = "+"
   If $bCountBlank = True Then $sChar = "*"
   Return StringRegExpReplace ($sString, "((." & $sChar & "\n){" & $iLine - 1 & "})(." & $sChar & "\n?)(." & $sChar & "\n*)", "\1\4")
EndFunc ; ==> _StringRemoveLine

Func _StringGetAfter ($sString, $sChar, $bFirst = True, $bCaseSense = False)
   Local $sGreed = "", $sCase = "(?i)"
   If $bFirst = False Then $sGreed = "(?u)"
   If $bCaseSense = True Then $sCase = ""
   Return StringRegExpReplace ($sString, $sCase & $sGreed & "(?s).*?\Q" & $sChar & "\E(.*)", "\1")
EndFunc ; ==> _StringGetAfter

Func _StringGetBefore ($sString, $sChar, $bFirst = True, $bCaseSense = False)
   Local $sGreed = "", $sCase = "(?i)"
   If $bFirst = False Then $sGreed = "(?u)"
   If $bCaseSense = True Then $sCase = ""
   Return StringRegExpReplace ($sString, $sGreed & "(?s)(.*?)\Q" & $sChar & "\E(.*)\z", "\1")
EndFunc ; ==> _StringGetBefore

Func _StringGetFirstLine ($sString)
   Return StringRegExpReplace ($sString, "\n.*", "")
EndFunc ; ==> _StringGetFirstLine

Func _StringGetLastLine ($sString)
   Return StringRegExpReplace ($sString, ".*\n", "")
EndFunc ; ==> _StringGetLastLine

Mat

Edited by Mat

Share this post


Link to post
Share on other sites
Authenticity

Nice functions. You can do a benchmark to see which approach is faster. For example, StringReplace is sometimes a faster and better alternative:

Just a simple benchmark:

Local $a = "ABA" & @CRLF & "CBC" & @CRLF & "DBD"
Local $b

For $i = 1 To 6
    $a &= $a
Next

Local $init = 0

$init = TimerInit()
For $i = 1 To 1000
    $b = UBound (StringRegExp ($a, "(\QB\E)", 3))
Next
ConsoleWrite($b & @TAB & TimerDiff($init) & @CRLF)

$init = TimerInit()
For  $i = 1 To 1000
    StringReplace($a, "B", "", 0, 1)
    $b = @extended
Next
ConsoleWrite($b & @TAB & TimerDiff($init) & @CRLF)

There is no difference in benching for case-(in)sensitivity.

Share this post


Link to post
Share on other sites
Mat

It could be interesting to see which methods favour longer + shorter strings though... Thats a very interesting set of results there though:

192 1258.41133440144
192 106.548457974407

I tried it on a considerably larger string (FileRead (WinApi.au3)), and StringReplace was considerably faster... From all the tests i've done, StringReplace has been faster actually :) ah well, its all that array handling, if I can find a way around that then I might be able to tighten the gap a bit. I should probably be using StringRegExp and reading that extended value... Yet testing on 6 winapi.au3's:

Local $a = FileRead (StringTrimRight (@AutoitEXE, 11) & "include\WinApi.au3")
Local $b

For $i = 1 To 6
    $a &= $a
Next

Local $init = 0

$init = TimerInit()
    StringRegExpReplace ($a, "(\Q_WinAPI_SetWindowLong\E)", "")
    $b = @Extended
$ret = $b & @TAB & TimerDiff($init) & @CRLF

$init = TimerInit()
    StringReplace($a, "_WinAPI_SetWindowLong", "", 0, 1)
    $b = @extended
$ret &= $b & @TAB & TimerDiff($init)

MsgBox (0, "Results!", $ret)

Mat

Edit: And into 4 digits at last!! I'm not going to post now just to keep on that magic 1000

Edited by Mat

Share this post


Link to post
Share on other sites
Authenticity

Just a tiny thing. $a &= $a is not x times $a but 2^x times what $a had at first. :)

Share this post


Link to post
Share on other sites
Mat

a few more than just six times then... :) ah well, minor detail and has very little relevence to the actual fact that stringReplace is considerably faster...

Mat

Share this post


Link to post
Share on other sites
Mat

No problem Zedna:

Func _StringAddLine ($sString, $iLine, $sLine, $bCountBlank = False)
   Local $sChar = "+"
   If $bCountBlank = True Then $sChar = "*"
   If Not IsInt ($iLine) Then Return SetError (1, 0, "")
   Return StringRegExpReplace ($sString, "((." & $sChar & "(\n)){" & $iLine & "})(?s)(." & $sChar & ")", "\1" & $sLine & "\3\4")
EndFunc ; ==> _StringAddLine

Mat

Edit: Now uses current line break character.

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  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.