rajeevsing15

Auto IT script for Finding/Replacing Multiple strings in Multiple files

17 posts in this topic

#1 ·  Posted

Hi All,

I am working on creating a script which can find a text from "Replace.txt" [Find anything which is before (|) and replace it with whatever after (|)] in multiple txlf files.

I have tried my best based on my experience but I couldn't get through. Can someone please help?

I am attaching my script here, with sample files.

Can someone please help out modifying this to meet my requirements?

Thanks In Advance

Rajeev

Replace.txt

Find_Replace.au3

File_to_change.txlf

Share this post


Link to post
Share on other sites



#2 ·  Posted

Moved to the appropriate forum


√-1 2^3 ∑ π, and it was delicious!

Share this post


Link to post
Share on other sites

#3 ·  Posted

Thanks :)

Share this post


Link to post
Share on other sites

#4 ·  Posted

Hi @rajeevsing15

This is how you could try to do it:

1°) use _FileReadToArray() to read the file replace.txt

2°) use _ArrayColInsert() to add a column to the array containin the replace.txt file lines

3°) use StringSplit() to split each line of replace.txt in two using "|" as a delimiter character and store the 2 result substrings in the 2 columns of the array.

This way the first column of the array contains the text to look for and the second column contains the text to replace to.

4°) Use FileRead() to read the .txlf file and find the text stored in the first column of the array. If found, use StringReplace() to replace the found text by the text stored in the 2nd column of the array.

5°) Save the modified file using FileWrite()

1 person likes this

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Thanks @Neutrofor replying. THese are very clean instructions and I tried to implement but didn't get any success. Maybe I am doing something wrong. Can you please look through my code below and point out?

#include <Array.au3>
#include <File.au3>
#include <GUIConstants.au3>
#include <GUIConstantsEx.au3>
Global $inputFile

$Form1 = GUICreate("Searching\Replacing SKUs", 510, 250, 256, 115,-1,BitOR($WS_EX_TOPMOST,$WS_EX_ACCEPTFILES))

            ;$MergeInputBrowse = GUICtrlCreateButton("Browse", 15, 20, 40, 20)
            $MergeInputPath = GUICtrlCreateInput('Paste path to xls files or click on "Browse..." to find it', 60, 20, 360, 20)
            GUICtrlSetState($MergeInputPath, $GUI_DROPACCEPTED)

            $MergeInputBrowsetxlf = GUICtrlCreateButton("Browse", 15, 60, 40, 20)
            $MergeInputPathTxlf = GUICtrlCreateInput('Paste path to TXLF files or click on "Browse..." to find it', 60, 60, 360, 20)
            GUICtrlSetState($MergeInputPathTxlf, $GUI_DROPACCEPTED)

            $Merge = GUICtrlCreateButton("Start!", 430, 20, 60, 20)
            $MergeProgress = GUICtrlCreateProgress(15,140, 480, 20)
            $MergeNotification = GUICtrlCreateInput("Ready to serve, my lord.", 15, 110, 480, 20,$ES_READONLY)

            $MergeProgress2 = GUICtrlCreateProgress(15,210, 480, 20)
            $MergeNotification2 = GUICtrlCreateInput("Ready to serve, my lord.", 15, 180, 480, 20,$ES_READONLY)

                GUICtrlCreateTabItem(""); The end of the tabs, this is needed to separate the last tab from other common elements of the GUI.

GUISetState(@SW_SHOW)

While 1
    $nMsg = GUIGetMsg()
    Select

        Case $nMsg = $MergeInputPath; updates the variable with the path entered in this, by pasting or by using the Browse.
            Global $inputFile = GUICtrlRead($MergeInputPath)


    EndSelect

    $nMsgtxlf = GUIGetMsg()
    Select
        Case $nMsgtxlf = $MergeInputBrowsetxlf
            $WorkingPath = FileSelectFolder("Select folder","")
            GUICtrlSetData($MergeInputPathTxlf,$WorkingPath)

        Case $nMsgtxlf = $MergeInputPathTxlf; updates the variable with the path entered in this, by pasting or by using the Browse.
            $WorkingPath = GUICtrlRead($MergeInputPathTxlf)

        Case $nMsgtxlf = $Merge
            FileChangeDir($WorkingPath)
            $PathsArraytxlf=_FileListToArrayRec($WorkingPath,"*.txlf",1,1)
            For $i = 1 to Ubound($PathsArraytxlf)-1
            GUICtrlSetData($MergeNotification, "Working on file " & $i & "/" & UBound($PathsArraytxlf)-1 & " : " & $PathsArraytxlf[$i])
            GUICtrlSetData($MergeProgress,($i)/(UBound($PathsArraytxlf)-1)*100)
            Replacer($PathsArraytxlf[$i])
            _ReduceMemory()
            Next
            MsgBox(0,"","Finished",0,$Form1)

        Case $nMsgtxlf = $GUI_EVENT_CLOSE
            Exit
         Case $nMsgtxlf = $GUI_EVENT_DROPPED
                ; If the value of @GUI_DropId is $idLabel, then set the label of the dragged file.


                If @GUI_DropId = $MergeInputPathTxlf Then
                    GUICtrlSetData($MergeInputPathTxlf, @GUI_DragFile)
                    $WorkingPath = GUICtrlRead($MergeInputPathTxlf)
                EndIf

    EndSelect

 WEnd


Func Replacer($nMsgtxlf); This one opens files in the path, one by one and makes the replacements.


   ;Reading TXLF files
    $iH = FileOpen(@WorkingDir&"\"&$nMsgtxlf,16384)
    $inContent = FileRead($iH)
    Local $readStrings

   ;Reading TXT file
   _FileReadToArray($inputFile, $readStrings)
   _ArrayColInsert($readStrings,1)
   $seperatedText = StringSplit("$readStrings", "|")

   Global $outContent
    $oH = StringReplace($inContent,"$seperatedText[0]","$seperatedText[1]")
    FileWrite($outContent,$oH)
    FileClose($outContent)

EndFunc

Func _ReduceMemory($i_PID = -1); function to reduce the RAM memory used by processes called from the script.
    If $i_PID <> -1 Then
        Local $ai_Handle = DllCall("kernel32.dll", 'int', 'OpenProcess', 'int', 0x1f0fff, 'int', False, 'int', $i_PID)
        $ai_Return = DllCall("psapi.dll", 'int', 'EmptyWorkingSet', 'long', $ai_Handle[0])
        DllCall('kernel32.dll', 'int', 'CloseHandle', 'int', $ai_Handle[0])
    Else
        $ai_Return = DllCall("psapi.dll", 'int', 'EmptyWorkingSet', 'long', -1)
    EndIf

    Return $ai_Return[0]
EndFunc   ;==>_ReduceMemory


 

 

Edited by rajeevsing15
Made a small change

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

Basically I would do it like this

#include <Array.au3>
#include <File.au3>

; this should be done only once
Local $array
_FileReadToArray("Replace.txt", $array, 1, "|")
_ArrayDisplay($array)

; you could loop here (eventually)
Local $file = "File_to_change.txlf", $content = FileRead($file)
For $i = 1 to $array[0][0]
   If StringInStr($content, $array[$i][0]) Then
       _ReplaceStringInFile($file, $array[$i][0], $array[$i][1])
       ExitLoop
   EndIf
Next

Edit
FileOpen not needed because it is done internally by both FileRead (for reading) and _ReplaceStringInFile (for writing)

Edited by mikell

Share this post


Link to post
Share on other sites

#7 ·  Posted

Thanks, @mikell for the reply.

I tried using this script but it only replaces one instance in a file. My requirement is, to replace all the occurrence of IDs in the first column of Array with IDs after (|) in Replace.txt

Also, I have to run this on tons of txlf files.  

I am very new to AutoIt and I am still learning. I Really appreciate your help here

Share this post


Link to post
Share on other sites

#8 ·  Posted

Strange... the default flag in _ReplaceStringInFile is 1 :  1 - all occurrences are replaced (default)
I tried with the files you provided in post #1 . In the .txlf file, there are 2 occurences of the first ID and both were replaced

Apparently, in the .txlf file there are several occurences of only one ID from Replace.txt, reason why I used Exitloop to make the script faster
Are your examples files representative ?

Share this post


Link to post
Share on other sites

#9 ·  Posted

@rajeevsing15

Just so you know, when you post in the forum you can use the "< >" button in the editor to post code :) So please  edit your previous post and put your code this way so we can read it better ;)

So this is the code that you posted that actually matters to doing what you want (the other is just GUI / file handling which i didn't check):

;Reading TXLF files
    $iH = FileOpen(@WorkingDir&"\"&$nMsgtxlf,16384)
    $inContent = FileRead($iH)
    Local $readStrings

   ;Reading TXT file
   _FileReadToArray($inputFile, $readStrings)
   _ArrayColInsert($readStrings,1)
   $seperatedText = StringSplit("$readStrings", "|")

   Global $outContent
    $oH = StringReplace($inContent,"$seperatedText[0]","$seperatedText[1]")
    FileWrite($outContent,$oH)
    FileClose($outContent)

Your first error is here:

$seperatedText = StringSplit("$readStrings", "|")

You put $readStrings between quotes " " but  $readStrings is a variable. If you put the variable name between quotes, it's taken into account as a string named "$separatedText" and no variable used.

So the correct thing here is:

$seperatedText = StringSplit($readStrings, "|")

Second error is here:

$seperatedText = StringSplit($readStrings, "|")

I understand the logic you used here. You thought, "hey, let's use stringsplit on the whole array at once!" :)

But it doesn't work this way :) I suggest you read this article about arrays to understand your mistake: https://www.autoitscript.com/wiki/Arrays

And this is not just specific to autoIT. Most programming languages work this way with arrays.

This is the correct version:

for $i = 1 to $readStrings[0][0] step 1

    $seperatedText = StringSplit($readStrings[$i][0], "|", 1)

    $readStrings[$i][0] = $seperatedText[1]
    $readStrings[$i][1] = $seperatedText[2]

Next

_ArrayDisplay($readStrings)

Once you understand how this works you can also correct the next part of the script ;)

Share this post


Link to post
Share on other sites

#10 ·  Posted

Rajeevsing15,

Did you try mikells code after removing the "exitloop"?  If i understand your task that should work.  All that is left is to feed your files in an outer loop.  You may want to back up the files first.

Kylomas


Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Share this post


Link to post
Share on other sites

#11 ·  Posted

kylomas,
You're right. My bad, I didn't pay attention enough to the whole content of the file. It should work if the Exitloop is removed indeed :>

Share this post


Link to post
Share on other sites

#12 ·  Posted

thanks, @mikell and @Neutro for the help and suggestions. I helped a lot in understanding the Array :)

I am all set with my script until I decided to take the "Replace.txt" with variable and then pass this file to the array but when I did so, I have got a very strange error and I keep on getting the same error even if I had done lots of modification.  Can you please look into the error I am getting and let me know which part is not right in below script.

I have attached "Replace.txt" and sample files in zip (In case you would like to test)

Error:
For $i 1 to $array[0][0]

                               ^

Error: Subscript used on non-accessible variable

Code:
 

#include <FileConstants.au3>
#include <MsgBoxConstants.au3>
#include <File.au3>
#include <Array.au3>
#include <Constants.au3>
#include <GUIConstants.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>

$path1 = ""
$path2 = ""
$path3 = ""
Global $array
Global $i
Global $Temp

$Form1 = GUICreate('Searching\Replacing SKUs in TXLF', 420, 150, -1, -1, -1, BitOR($WS_EX_TOPMOST, $WS_EX_ACCEPTFILES)) ; will create a dialog box
;$browse2 = GUICtrlCreateButton("Browse...", 10, 20, 70, 20) ; will display a button
Global $idFile2 = GUICtrlCreateInput('Drag and Drop TXT file with SKU', 90, 20, 320, 20)
GUICtrlSetState($idFile2, $GUI_DROPACCEPTED)

Global $browse3 = GUICtrlCreateButton("Browse...", 10, 60, 70, 20) ; will display a button
Global $idPath3 = GUICtrlCreateInput('Paste path to "TXLF" files or click on "Browse..." to find it', 90, 60, 320, 20) ; will display a section to paste the path where files to be renamed should be

$MaxlenButton = GUICtrlCreateButton("Submit", 140, 90, 120, 40)
;Local $text3 = GUICtrlCreateLabel("Maxlen to be set in all cells:", 10, 80, 140, 20)

;_FileReadToArray("Replace.txt", $array, 1, "|")

GUISetState(@SW_SHOW) ; will display a dialog box

Local $idMsg

; Loop until the user exits.
While 1
MsgBox(1, "Test", $idFile2)

Switch GUIGetMsg()
       Case $browse3
            $path3 = FileSelectFolder("Select folder", "") & "\" ; Displays a window to select a folder and adds "\" to the path selected.
            GUICtrlSetData($idPath3, $path3) ; Updates the value of the $idPath variable (assigned to the section to paste the path) with the previously selected path.
            FileChangeDir($path3) ; Changes the working directory to the previously selected path.

        Case $idPath3
            $path3 = GUICtrlRead($idPath3) ; Reads the written content in the section assigned to paste the path.
            FileChangeDir($path3) ; Changes the working directory to the previously selected path.
        Case $GUI_EVENT_CLOSE ; closes the dialog box (including Constants required).
            Exit

        Case $MaxlenButton

            $TermsList = GUICtrlRead($idPath3)

            If $path3 = "" Then ; If no path is provided, error message will appear.
                MsgBox(0, "Error", "Error: Please select path to files including \ at the end")
                ContinueLoop
            EndIf
            If $path3 = "\" Then ; If browse button is clicked but no folder is selected, it will automatically generate "\" and if submitted, error message will appear.

                MsgBox(0, "Error", "Error: Please select path to files including \ at the end")
                ContinueLoop
            EndIf
            _Maxlen() ; will run _FileQA function

    EndSwitch
WEnd

Func _Maxlen()
   _FileReadToArray($idFile2, $array, 1, "|")
   _ArrayDisplay($array)

    ProgressOn("Replacing SKUs...", "Working on it...", "", 500, 10, 16)

    $TxmlFiles = _FileListToArrayRec($path3, "*.txlf", 1, 1, 1, 2)
    _ArrayDelete($TxmlFiles, 0)

    ;$FileNumberQA = 0

    $FileID = 0
    $filearray = UBound($TxmlFiles)

    For $Txml In $TxmlFiles
        $FileID += 1
        $Progress = $FileID / $filearray * 100
        ProgressSet($Progress, $FileID & " out of " & $filearray & " files checked...")

        $content = FileRead($Txml)
      For $i = 1 to $array[0][0]
      If StringInStr($content, $array[$i][0]) Then
      _ReplaceStringInFile($Txml, $array[$i][0], $array[$i][1])
       ;ExitLoop
      EndIf
   Next


    Next
    ProgressOff()
    MsgBox(0, 'Done', 'SKU Replaced')

EndFunc   ;==>_Maxlen

MsgBox(0 + 64, 'Complete', 'Process complete')


Func _ReduceMemory($i_PID = -1) ; function to reduce the RAM memory used by processes called from the script.
    If $i_PID <> -1 Then
        Local $ai_Handle = DllCall("kernel32.dll", 'int', 'OpenProcess', 'int', 0x1f0fff, 'int', False, 'int', $i_PID)
        $ai_Return = DllCall("psapi.dll", 'int', 'EmptyWorkingSet', 'long', $ai_Handle[0])
        DllCall('kernel32.dll', 'int', 'CloseHandle', 'int', $ai_Handle[0])
    Else
        $ai_Return = DllCall("psapi.dll", 'int', 'EmptyWorkingSet', 'long', -1)
    EndIf

    Return $ai_Return[0]
EndFunc   ;==>_ReduceMemory

 

 

Test_Files.zip

Replace.txt

Share this post


Link to post
Share on other sites

#14 ·  Posted

@rajeevsing15

The problem is that you're trying to do too much things at once and then everything fails :)

You're trying to use a GUI, work with multiple files while you can't even do it for 1 file without a GUI!

When you get dressed up you dont try to put all your clothes at once, you put your pants then your shirt ect... You need to do the same here :D

So for now focus on replacing the text ONLY in the example file you posted in your first message.

Once you get it right, you can work on using a GUI, then when this is working you can add working with multiple files :)

So start from here:

#include <Array.au3>
#include <File.au3>

;Reading TXLF file

$iH = FileOpen(@WorkingDir & "\File_to_change.txlf")

$inContent = FileRead($iH)

;Reading TXT file

Local $readStrings

_FileReadToArray(@ScriptDir & "\Replace.txt", $readStrings)

_ArrayColInsert($readStrings, 1)

For $i = 1 To $readStrings[0][0] Step 1

    $seperatedText = StringSplit($readStrings[$i][0], "|", 1)

    $readStrings[$i][0] = $seperatedText[1]
    $readStrings[$i][1] = $seperatedText[2]

Next

_ArrayDisplay($readStrings)

And try from there to figure out the code to replace the text inside $inContent with the text contained in the array $readStrings ;)

Share this post


Link to post
Share on other sites

#16 ·  Posted

25 minutes ago, Neutro said:

@rajeevsing15

The problem is that you're trying to do too much things at once and then everything fails :)

You're trying to use a GUI, work with multiple files while you can't even do it for 1 file without a GUI!

When you get dressed up you dont try to put all your clothes at once, you put your pants then your shirt ect... You need to do the same here :D

So for now focus on replacing the text ONLY in the example file you posted in your first message.

Once you get it right, you can work on using a GUI, then when this is working you can add working with multiple files :)

So start from here:

#include <Array.au3>
#include <File.au3>

;Reading TXLF file

$iH = FileOpen(@WorkingDir & "\File_to_change.txlf")

$inContent = FileRead($iH)

;Reading TXT file

Local $readStrings

_FileReadToArray(@ScriptDir & "\Replace.txt", $readStrings)

_ArrayColInsert($readStrings, 1)

For $i = 1 To $readStrings[0][0] Step 1

    $seperatedText = StringSplit($readStrings[$i][0], "|", 1)

    $readStrings[$i][0] = $seperatedText[1]
    $readStrings[$i][1] = $seperatedText[2]

Next

_ArrayDisplay($readStrings)

And try from there to figure out the code to replace the text inside $inContent with the text contained in the array $readStrings ;)

Thanks For the suggestion brother.

Share this post


Link to post
Share on other sites

#17 ·  Posted

@rajeevsing15

Glad I could help
About details : the little changes below are absolutely not essential but they make your code flow nicely like a clear stream  :)

Func _Maxlen()
   _FileReadToArray($idFile2, $array, 1, "|")
  ; _ArrayDisplay($array)

    ProgressOn("Replacing SKUs...", "Working on it...", "", 500, 10, 16)

    Local $TxmlFiles = _FileListToArrayRec($path3, "*.txlf", 1, 1, 1, 2)
    $filearray = $TxmlFiles[0]

    For $n = 1 to $filearray
        $Progress = $n / $filearray * 100
        ProgressSet($Progress, $n & " out of " & $filearray & " files checked...")

        $content = FileRead($TxmlFiles[$n])
        For $i = 1 to $array[0][0]
           If StringInStr($content, $array[$i][0]) Then
              _ReplaceStringInFile($TxmlFiles[$n], $array[$i][0], $array[$i][1])
           EndIf
        Next
    Next

    ProgressOff()
    MsgBox(0, 'Done', 'SKU Replaced')
EndFunc   ;==>_Maxlen

 

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