hawkair

Insert Line Numbers in text with Stringregexpreplace

13 posts in this topic

Hi

I am trying to insert line numbers in to a string

with this script

Func _MyInc ()
Static Local $i = 0
$i += 1
Return $i
EndFunc

Exit _InsertLines()
Func _InsertLines()
    $String = "A" & @CRLF & "B" & @CRLF & "C" & @CRLF & "D"
    $NewString =  Execute("'" & StringRegExpReplace($String,"[\r\n]*",  "' & _MyInc () & '\1" ) & "'")
    MsgBox (0, "", $NewString)
EndFunc

but I get this:

1A23B45C67D8

I never really could master how Execute works here and I always get some working example and make substitutions.

But this is the closest i could get...

 

Share this post


Link to post
Share on other sites



Here's an interesting Stack Overflow thread about using an increasing counter in Regex: http://stackoverflow.com/questions/12941362/is-it-possible-to-increment-numbers-using-regex-substitution

But I would personally go for something simpler like this:

#include <StringConstants.au3>
#include <Array.au3>

$LINE_INCREMENT = 10

$string = "A" & @CRLF & "B" & @CRLF & "C" & @CRLF & "D"
$aLines = StringSplit($string, @CRLF, $STR_ENTIRESPLIT + $STR_NOCOUNT)

For $iLine = 0 to UBound($aLines) - 1
    $aLines[$iLine] = (($iLine + 1) * $LINE_INCREMENT) & " " & $aLines[$iLine]
Next

$newString = _ArrayToString($aLines, @CRLF)

MsgBox(0, 0, $newString)

Unless the texts get really really big, then I'd probably just use a Powershell oneliner.


Roses are FF0000, violets are 0000FF... All my base are belong to you.

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Thanks SadBunny

I actually wanted to avoid stringsplits and For Loops

I believe I got it correct now (after many trials of quote placing...)

I also include a formatted version for line numbers

Func _MyInc ()
Static Local $i = 0
$i += 1
Return $i
EndFunc

Func _InsertLines()
        $String = "A" & @CRLF & "B" & @CRLF & "C" & @CRLF & "D" & @CRLF & "A" & @CRLF & "B" & @CRLF & "C" & @CRLF & "D" & @CRLF & "A" & @CRLF & "B" & @CRLF & "C" & @CRLF & "D"

    $NewString =  StringTrimLeft (Execute("'" & StringRegExpReplace($String,"(?|\A|[\r\n]+)",  @CRLF & "' & _MyInc () & '." ) & "'"), 2)
    MsgBox (0, "", $NewString)
    $NewString =  StringTrimLeft (Execute("'" & StringRegExpReplace($String,"(?|\A|[\r\n]+)",  @CRLF & "' & StringFormat (""%3d"", _MyInc ()) & '." ) & "'"), 2)
    MsgBox (0, "", $NewString)
EndFunc

_InsertLines()

 

A word of caution though. There are problems (I just verified it) with this solution

if $String contains single quotes ('). Execute gets confused.

So either search and replace ' with something unique like say "[singlequote]"

or go with Sadbunnys solution

 

Edited by hawkair
Added Word of caution

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

I was trying to be creative and keep this just inside the StringRegExp() to do everything, but looks like even though I have a function to increment the line numbers that the replacement part of StringRegExp only calls the function one time instead of each time it does a replacement. 

Global $iCount = 0
$String = "A" & @CRLF & "B" & @CRLF & "C" & @CRLF & "D"
$NewString = StringRegExpReplace($String, "([^\r\n])", FuncCounter($iCount) & " " & "$1")
MsgBox(0, "", $NewString)


Func FuncCounter(ByRef $iCount)
$iCount = $iCount +1
Return $iCount
EndFunc

I have a lingering feeling that there is still a way to do it in a similar manner in where the RegExp itself returns the number of replacements it has made and that could be the increment factor. 

Edited by ViciousXUSMC

Share this post


Link to post
Share on other sites

That can't be done in a single PCRE regexp, I mean without external code. It can be done in Perl for instance (see (?p{...}) in the PCRE pattern documentation), but this implies Perl interpolating code, which is somehow cheating, similar to the concatenation with Execute.

To avoid single quotes breaking things, wrap the string part with StringReplace($s, "'", "''"). Also \R is efficient to match a line termination.


This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites
6 hours ago, jchd said:

,,,,  concatenation with Execute  ....

An example of the ' concatenation with Execute' as mentioned above.

Local $String = "A1" & @CRLF & "B2" & @CRLF & "C3" & @CRLF & "D4" ;& @CRLF

Local $NewString = '"1: " & "' & StringRegExpReplace($String, "(\R)", '$1" & _Counter() & ": ') & '"'
ConsoleWrite($NewString & @LF)
MsgBox(0, "Results", Execute($NewString))


Func _Counter()
    Local Static $iCount = 1
    $iCount += 1
    Return $iCount
EndFunc   ;==>_Counter

 

1 person likes this

Share this post


Link to post
Share on other sites

:blink:

Wow... How does that work? How is _Counter executed more than once?


Roses are FF0000, violets are 0000FF... All my base are belong to you.

Share this post


Link to post
Share on other sites

... and here is the jguinch's way applied to Malkey's example   :)

Local $String = "A1" & @CRLF & "B2" & @CRLF & "C3" & @CRLF & "D4" ;& @CRLF
Local $i = 1
Local $NewString = '$i & ": " & "' & StringRegExpReplace($String, "(\R)", _ 
                    '$1" & Assign("i", Eval("i")+1)*Eval("i") & ": ') & '"'

ConsoleWrite($NewString & @LF)
MsgBox(0, "Results", Execute($NewString))

 

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

I was preparing the reply  ;)

mine is almost the same :

Local $sString = "A1" & @CRLF & "B2" & @CRLF & "C3" & @CRLF & "D4"
$sOutput = Execute ( "'" & StringRegExpReplace(  StringReplace($sString, "'", "''")  , "(?m)^", "' & (Assign(""iReplace"", Eval(""iReplace"") + 1) * 0 + Eval(""iReplace"")) & ' - ") & "'" )
MsgBox(0, "", $sOutput)

 

Edited by jguinch

Share this post


Link to post
Share on other sites

Sorry ... :P

Share this post


Link to post
Share on other sites

Damn, them's some pretty nifty pieces of code! :drool:


Roses are FF0000, violets are 0000FF... All my base are belong to you.

Share this post


Link to post
Share on other sites
12 hours ago, Malkey said:

An example of the ' concatenation with Execute' as mentioned above.

Local $String = "A1" & @CRLF & "B2" & @CRLF & "C3" & @CRLF & "D4" ;& @CRLF

Local $NewString = '"1: " & "' & StringRegExpReplace($String, "(\R)", '$1" & _Counter() & ": ') & '"'
ConsoleWrite($NewString & @LF)
MsgBox(0, "Results", Execute($NewString))


Func _Counter()
    Local Static $iCount = 1
    $iCount += 1
    Return $iCount
EndFunc   ;==>_Counter

 

This seems the similar of the above.

How does this work exactly?  I notice just adding Execute() to my code does not work so its not like magic, definitely more to it. 

Share this post


Link to post
Share on other sites

Another method that doesn't rely on execute trickery, using a function I wrote for using callbacks with regex.

Local $sInput = "This is a test." & @CRLF & "Line 2" & @CRLF & "Line 3" & @CRLF & "Line 4" & @CRLF & "Line 5" & @CRLF & "Line 6"

Local $sTest = "1: " & StringRegExpReplaceCallback($sInput, "\R", _Callback)

MsgBox(0, "Test", $sTest)

Func _Callback($aRes)
    Local Static $iCount = 1
    $iCount += 1
    Return @CRLF & $iCount & ": "
EndFunc

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

 

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

  • Similar Content

    • ViciousXUSMC
      By ViciousXUSMC
      So I ran into this crazy "program" that cant be uninstalled via WMI, MSIExec, etc.
      The only way to uninstall it was from Add/Remove programs manually... Or I found if you find it in the registry under HKCU and run the  uninstall string, it will also uninstall.
      However the string in the registry cant be run directly in a cmd window because of the format errors.
      It has spaces without quotations, it has invalid characters, etc, etc 
      I know things run different when executed in the registry, so maybe there is a way I can run the regsitry key just like how the system does?  If so chime in.
      Otherwise I did this a crude way using several stringregexpreplace() functions and have it working.
      The solution feels so barbaric and crude that I wanted to post it so some of you guys better than me can clean up the code, maybe offer alternative ways to do it, or reduce the number of times I process the string.
      Here is the string right out of the registry:
      c:\Program Files\Common Files\Microsoft Shared\VSTO\10.0\VSTOInstaller.exe /Uninstall file:///C:/Users/it022565/AppData/Local/Temp/OOBAXTOWordAddIn/ApplicationXtender.AXTO.Word.vsto Here is my cave man scripting to turn this into a run able string.
       
      Func _UninstallOld() For $i = 1 to 100 ;Enumerate Registry $sEnumBase = "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" ;Look in HKCU for the uninstall string for the old version $sEnum = RegEnumKey($sEnumBase, $i) If @Error Then Return If $iDebug = 1 Then MsgBox(0, "", $sEnum) If StringInStr(RegRead($sEnumBase & $sEnum, "DisplayName"), "Word Addin") Then ExitLoop Next If $iDebug = 1 Then MsgBox(0, "", $sEnum) $sKey = "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" & $sEnum $sKey2 = RegRead($sKey, "UninstallString") If $iDebug = 1 Then MsgBox(0, "Original Install Location", $sKey2) $sKey3 = StringRegExpReplace($sKey2, "(?i)(c:.*exe)", '"$1"') If $iDebug = 1 Then MsgBox(0, "", $sKey3) $sKey4 = StringRegExpReplace($sKey3, "(?i)file:///", "") If $iDebug = 1 Then MsgBox(0, "", $sKey4) $sKey5 = StringRegExpReplace($sKey4, "%20", " ") If $iDebug = 1 Then MsgBox(0, "", $sKey5) $sKey6 = StringRegExpReplace($sKey5, '(?i)((?<!")c:.*vsto)', '"$1"') If $iDebug = 1 Then MsgBox(0, "", $sKey6) RunWait(@ComSpec & ' /c ' & '"' & $sKey6 & ' /s"', "", @SW_HIDE) EndFunc Basically step by step I add quotations, strip bad characters, etc.  Kind of proud for using look behind for once
      Looking forward to what you guys come up with.
    • VIP
      By VIP
      Need help to make function better  with full infomation
      #include <Array.au3> #include <File.au3> _TEST(@ScriptFullPath) _TEST("A:") _TEST("A:\B.c") _TEST("D:\E\F\") _TEST("G:\H/../J.k/") _TEST("M:\N\k..J.k") _TEST("D:\E\F\..\G\G\I..J.K.M") Func _TEST($sFilePath) Local $sDrive = "", $sFullPathDir = "", $sDirPath = "", $sDirName = "", $sFileName = "", $sFileNameExt = "", $sExtension = "", $sExt = "" Local $aPathSplit = _PathSplitByRef($sFilePath, $sDrive, $sFullPathDir, $sDirPath, $sDirName, $sFileName, $sFileNameExt, $sExtension, $sExt) ConsoleWrite("!Path IN : " & $sFilePath & @CRLF) ; C:\Windows\System32\etc\hosts.exe ConsoleWrite("- Driver : " & $sDrive & @CRLF) ; C: ConsoleWrite("- DirPath : " & $sFullPathDir & @CRLF) ; C:\Windows\System32\etc\etc ConsoleWrite("- DirPath : " & $sDirPath & @CRLF) ; \Windows\System32\etc\ ConsoleWrite("- DirName : " & $sDirName & @CRLF) ; etc ConsoleWrite("- FileName : " & $sFileName & @CRLF) ; hosts ConsoleWrite("- FileNameExt: " & $sFileNameExt & @CRLF) ; hosts.exe ConsoleWrite("- Extension : " & $sExtension & @CRLF) ; .exe ConsoleWrite("- Ext : " & $sExt & @CRLF & @CRLF) ; exe ;~ ConsoleWrite("!Path IN : " & $aPathSplit[0] & @CRLF) ; C:\Windows\System32\etc\hosts.exe ;~ ConsoleWrite("- Driver : " & $aPathSplit[1] & @CRLF) ; C: ;~ ConsoleWrite("- DirPath : " & $aPathSplit[2] & @CRLF) ; C:\Windows\System32\etc\etc ;~ ConsoleWrite("- DirPath : " & $aPathSplit[3] & @CRLF) ; \Windows\System32\etc\ ;~ ConsoleWrite("- DirName : " & $aPathSplit[4] & @CRLF) ; etc ;~ ConsoleWrite("- FileName : " & $aPathSplit[5] & @CRLF) ; hosts ;~ ConsoleWrite("- FileNameExt: " & $aPathSplit[6] & @CRLF) ; hosts.exe ;~ ConsoleWrite("- Extension : " & $aPathSplit[7] & @CRLF) ; .exe ;~ ConsoleWrite("- Ext : " & $aPathSplit[8] & @CRLF) ; exe ;~ _ArrayDisplay($aPathSplit, "_PathSplit of " & $sFilePath) EndFunc ;==>_TEST Func _PathSplitByRef($sFilePath, ByRef $sDrive, ByRef $sFullPathDir, ByRef $sDirPath, ByRef $sDirName, ByRef $sFileName, ByRef $sFileNameExt, ByRef $sExtension, ByRef $sExt) If StringInStr($sFilePath,"..") Then $sFilePath=_PathFull($sFilePath) Local $aPartOfPath=StringRegExp($sFilePath, "^\h*((?:\\\\\?\\)*(\\\\[^\?\/\\]+|[A-Za-z]:)?(.*[\/\\]\h*)?((?:[^\.\/\\]|(?(?=\.[^\/\\]*\.)\.))*)?([^\/\\]*))$", $STR_REGEXPARRAYMATCH) ;~ If @error Then ReDim $aPartOfPath[9] ;~ $aPartOfPath[0] = $sFilePath ;~ EndIf $aPartOfPath[0] = $sFilePath ; C:\Windows\System32\etc\hosts.exe $sDrive = $aPartOfPath[1] ; C: $sFullPathDir = $aPartOfPath[1] & $aPartOfPath[2] ; C:\Windows\System32\etc If StringLeft($aPartOfPath[2], 1) == "/" Then $sDirPath = StringRegExpReplace($aPartOfPath[2], "\h*[\/\\]+\h*", "\/") Else $sDirPath = StringRegExpReplace($aPartOfPath[2], "\h*[\/\\]+\h*", "\\") EndIf $aPartOfPath[2] = $sFullPathDir ; C:\Windows\System32\etc $sDirName=StringReplace($sDirPath,"\","") $sDirName=StringReplace($sDirPath,"/","") $sFileName = $aPartOfPath[3] ; hosts $aPartOfPath[5] = $sFileName ; hosts $sExtension = $aPartOfPath[4] ; .exe $aPartOfPath[7] = $sExtension ; .exe $aPartOfPath[3] = $sDirPath ; \Windows\System32\etc\ $aPartOfPath[4] = $sDirName ; etc $aPartOfPath[6] = $sFileName & $sExtension ; hosts.exe $sFileNameExt = $aPartOfPath[6] ; hosts.exe $sExt = StringReplace($sExtension,".","") ; exe $aPartOfPath[8] = $sExt ; exe Return $aPartOfPath EndFunc ;==>_PathSplitByRef  
    • cherrylatte
      By cherrylatte
      hi
      I'm trying to execute files 
      I want it to run in order.
      for instance, if there's folder like below, I want to run 1.exe > 2.exe > 3.exe
      root folder
        |___folder 1 > 1.exe
        |___folder2 > 2.exe
        |___folder3 > 3.exe
       
      What I did to do the above, was to make a text file that contains the path to each of those files and put those in array form.
      but copying and pasting every path of those files into a text file is very exhausting thing to do when there's like hundreds of files to execute.
      So I was wondering if there is a simple way to run those files.
      I'd be thankful if anybody answers it. 
       
       
    • LegitStack
      By LegitStack
      Is there a way to execute the text inside a variable is if it was part of the script?
      In this example I'd like to get a message box pop up but I don't: 
      ;testme.au3   local $var = 'msgbox(64,"hello","world")'   $var is there a command that can be used like maybe 'Exec' or 'Execute' or something?
        local $var = 'msgbox(64,"hello","world")'   Execute $var  
    • AutoBert
      By AutoBert
      The idea to use translation api:

      i used the script from @mikell to build this func:
      Func _Translate($sFrom, $from, $to) ;thanks to mikell (autoitscript.com) ;https://www.autoitscript.com/forum/topic/182893-prompt-me-how-to-see-the-text-in-the-translation-boxhttpstranslategooglecom/?do=findComment&comment=1313423 Local $url = "https://translate.googleapis.com/translate_a/single?client=gtx" $url &= "&sl=" & $from & "&tl=" & $to & "&dt=t&q=" & $sFrom Local $oHTTP = ObjCreate("Microsoft.XMLHTTP") $oHTTP.Open("POST", $url, False) $oHTTP.Send() Local $sData = $oHTTP.ResponseText $sData = StringRegExpReplace($sData, '.*?\["(.*?)"[^\[]*', "$1" & @CRLF) Return $sData EndFunc ;==>_Translate when i call this func with:
      $sText='AutoIt v3 is a freeware BASIC-like scripting language designed for automating the Windows GUI and general scripting. It uses a combination of simulated keystrokes, mouse movement and window/control manipulation in order to automate tasks in a way not possible or reliable with other languages (e.g. VBScript and SendKeys). AutoIt is also very small, self-contained and will run on all versions of Windows out-of-the-box with no annoying "runtimes" required!' MsgBox(64,'',_Translate($sText,'en','de')) nearly all is seeing here:

      only the "!" is wrong "\" but when using 'auto' instead of 'en' the result is:

      2 lines are appended. So my question is, is it possible to extend the pattern (i never worked with regex) and in best case setting @extended with the detected language?
      @Trong: as you can see yet i am returning translated text and don't use GuiCtrlSetData to assign it to a EditBox.