More advanced replace text in file

From NSIS Wiki
Jump to navigationJump to search
Author: Afrow UK (talk, contrib)


Description

This function allows you to replace pieces of text in a file. You have the option of replacing text from the xth times of its occurring, and y times replacement of the text from that xth occurrence onwards. Just copy the full code underneath in a text file with notepad, rename it: ReplaceInFile3.nsh and save it in the Include folder of your NSIS installation folder. You should run your installer.exe file in administrator mode which grants you authorization for modifying files in directories (Otherwise the code will be overlooked with no warning).

Usage 0

OutFile "my_installer.exe"
 
;--- maybe some code here
 
!include ReplaceInFile3.nsh
 
;--- maybe some code here
 
Section "my_section"
 
;--- maybe some code here
 
StrCpy $OLD_STR 'the_old_string'
StrCpy $FST_OCC all
StrCpy $FST_OCC 2
StrCpy $NR_OCC all
StrCpy $NR_OCC 3
StrCpy $REPLACEMENT_STR 'the_new_string'
StrCpy $FILE_TO_MODIFIED 'the_file_to_be_modified'
 
!insertmacro ReplaceInFile $OLD_STR $FST_OCC $NR_OCC $REPLACEMENT_STR $FILE_TO_MODIFIED ;job done
 
;MessageBox MB_OK|MB_ICONINFORMATION "REPLACEMENT_STR = $REPLACEMENT_STR"
 
;--- maybe some code here
 
SectionEnd

Usage 1

Push hello #text to be replaced
Push blah #replace with
Push 3 #start replacing at the 3rd occurrence
Push 4 #replace 4 occurrences onwards, in all
Push temp1.bat #file to replace in, in the current directory
 Call AdvReplaceInFile

Usage 2

Push hello #text to be replaced
Push blah #replace with
Push 3 #start replacing at 3rd occurrence
Push all #replace all other occurrences
Push C:\temp1.bat #file to replace in
 Call AdvReplaceInFile

Usage 3

Push hello #text to be replaced
Push blah #replace with
Push all #replace all occurrences
Push all #replace all occurrences
Push 'C:\Program Files\temp1.info' #file to replace in
 Call AdvReplaceInFile

Code

/*
First occurrence to be replaced: FST_OCC. 
   FST_OCC = all, renders the same as FST_OCC = 1.
   if FST_OCC greater than the number of occurences in the file: no alteration of the file,
   FST_OCC negative or 0 will leave the file content unchanged no matter the NR_OCC value. 
Nr max of occurrences replaced onwards: NR_OCC,
   if NR_OCC = all --> replacement as long as a string to be replaced is found,
   if NR_OCC = stritly positive integer, replaces up to NR_OCC occurrences provided they exist,   
   NR_OCC negative or 0 yields the same as all.
 
Order to run down and search the file: from left to right and top down.
REPLACEMENT_STR, OLD_STR, read line should be less than 1024 characters long. 
For NSIS Unicode, FILE_TO_MODIFIED must be utf-8 encoded.																	
*/
 
Var /Global OLD_STR
Var /Global FST_OCC
Var /Global NR_OCC
Var /Global REPLACEMENT_STR
Var /Global FILE_TO_MODIFIED
 
!macro ReplaceInFile OLD_STR FST_OCC NR_OCC REPLACEMENT_STR FILE_TO_MODIFIED
 
        Push "${OLD_STR}" ;text to be replaced
	Push "${REPLACEMENT_STR}" ;replace with
	Push "${FST_OCC}" ; starts replacing onwards FST_OCC occurrences
	Push "${NR_OCC}" ; replaces NR_OCC occurrences in all
	Push "${FILE_TO_MODIFIED}" ; file to replace in
	Call AdvReplaceInFile
 
!macroend
 
 
Function AdvReplaceInFile
Exch $0 ;FILE_TO_MODIFIED file to replace in
Exch
Exch $1 ;the NR_OCC of OLD_STR occurrences to be replaced.
Exch
Exch 2
Exch $2 ;FST_OCC: the first occurrence to be replaced and onwards
Exch 2
Exch 3
Exch $3 ;REPLACEMENT_STR string to replace with
Exch 3
Exch 4
Exch $4 ;OLD_STR to be replaced
Exch 4
Push $5 ;incrementing counter
Push $6 ;a chunk of read line
Push $7 ;the read line altered or not
Push $8 ;left string
Push $9 ;right string or forster read line
Push $R0 ;temp file handle
Push $R1 ;FILE_TO_MODIFIED file handle
Push $R2 ;a line read
Push $R3 ;the length of OLD_STR
Push $R4 ;counts reaching of FST_OCC
Push $R5 ;counts reaching of NR_OCC
Push $R6 ;temp file name
 
 
  GetTempFileName $R6
 
  FileOpen $R1 $0 r 			;FILE_TO_MODIFIED file to search in
  FileOpen $R0 $R6 w                    ;temp file
   StrLen $R3 $4			;the length of OLD_STR
   StrCpy $R4 0				;counter initialization
   StrCpy $R5 -1			;counter initialization
 
loop_read:
 ClearErrors
 FileRead $R1 $R2 			;reading line
 IfErrors exit				;when end of file has been reached
 
   StrCpy $5 -1  			;cursor, start of read line chunk
   StrLen $7 $R2 			;read line length
   IntOp $5 $5 - $7			;cursor initialization
   StrCpy $7 $R2			;$7 contains read line
 
loop_filter:
   IntOp $5 $5 + 1 			;cursor shifting
   StrCmp $5 0 file_write		;end of line has been reached
   StrCpy $6 $7 $R3 $5 			;a chunk of read line of length OLD_STR 
   StrCmp $6 $4 0 loop_filter		;continues to search OLD_STR if no match
 
StrCpy $8 $7 $5 			;left part 
IntOp $6 $5 + $R3
IntCmp $6 0 yes no			;left part + OLD_STR == full line read ?						
yes:
StrCpy $9 ""
Goto done
no:
StrCpy $9 $7 "" $6 			;right part
done:
StrCpy $9 $8$3$9 			;replacing OLD_STR by REPLACEMENT_STR in forster read line
 
IntOp $R4 $R4 + 1			;counter incrementation
;MessageBox MB_OK|MB_ICONINFORMATION \
;"count R4 = $R4, fst_occ = $2" 
StrCmp $2 all follow_up			;exchange ok, then goes to search the next OLD_STR
IntCmp $R4 $2 follow_up			;no exchange until FST_OCC has been reached,
Goto loop_filter			;and then searching for the next OLD_STR
 
follow_up:	
IntOp $R4 $R4 - 1			;now counter is to be stuck to FST_OCC
 
IntOp $R5 $R5 + 1			;counter incrementation
;MessageBox MB_OK|MB_ICONINFORMATION \
;"count R5 = $R5, nbr_occ = $1" 
StrCmp $1 all exchange_ok 		;goes to exchange OLD_STR with REPLACEMENT_STR
IntCmp $R5 $1 finalize			;proceeding exchange until NR_OCC has been reached														
 
exchange_ok:
IntOp $5 $5 + $R3 			;updating cursor
StrCpy $7 $9				;updating read line with forster read line
Goto loop_filter			;goes searching the same read line
 
finalize:
IntOp $R5 $R5 - 1			;now counter is to be stuck to NR_OCC
 
file_write: 
 FileWrite $R0 $7 			;writes altered or unaltered line 
Goto loop_read				;reads the next line
 
exit:
  FileClose $R0
  FileClose $R1
 
   ;SetDetailsPrint none
  Delete $0
  Rename $R6 $0				;superseding FILE_TO_MODIFIED file with
					;temp file built with REPLACEMENT_STR 
  ;Delete $R6
   ;SetDetailsPrint lastused
 
Pop $R6
Pop $R5
Pop $R4
Pop $R3
Pop $R2
Pop $R1
Pop $R0
Pop $9
Pop $8
Pop $7
Pop $6
Pop $5
;These values are stored in the stack in the reverse order they were pushed
Pop $0
Pop $1
Pop $2
Pop $3
Pop $4
FunctionEnd

Versions History

2020-12-12
Mild alterations to make it work, and such as it was intended to in the first place. Pascal Dor.
bug: scans the read line from right to left
bug: doesn't do the job unless: FST_OCC = NR_OCC = all, and even so not fully.
2010-10-09
Bug fixed that doesn't change "all" occurrences
2006-09-28
Bug fixed that restoring $0~$4 order -- Maxi Ng
2005-July-18
Bug fixed that doesn't replace a text when you have only 1 line in the text file - Mark Bryan Yu
2004-Feb-18
Bug fixed that stopped it replacing parts of text on a line. The bug was only allowing it to replace whole lines.
2003-May-27
Re-written.

Credits

Written by me for modifying batch files.

-Stu (Afrow UK)