More advanced replace text in file: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
(Restore with SetDetailsPrint lastused)
 
(41 intermediate revisions by the same user not shown)
Line 3: Line 3:
== Description ==
== Description ==
This function allows you to replace pieces of text in a file.
This function allows you to replace pieces of text in a file.
Instead of replacing all text found in the file, you have the extra option of replacing text after the x times of it occurring, and x times to replace the text after that occurrence.
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 ==
<highlight-nsis>
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
</highlight-nsis>


== Usage 1 ==
== Usage 1 ==
Line 9: Line 41:
Push hello #text to be replaced
Push hello #text to be replaced
Push blah #replace with
Push blah #replace with
Push 3 #start replacing after 3rd occurrence
Push 3 #start replacing at the 3rd occurrence
Push 4 #replace next 4 occurrences
Push 4 #replace 4 occurrences onwards, in all
Push C:\temp1.bat #file to replace in
Push temp1.bat #file to replace in, in the current directory
  Call AdvReplaceInFile
  Call AdvReplaceInFile
</highlight-nsis>
</highlight-nsis>
Line 19: Line 51:
Push hello #text to be replaced
Push hello #text to be replaced
Push blah #replace with
Push blah #replace with
Push 3 #start replacing after 3rd occurrence
Push 3 #start replacing at 3rd occurrence
Push all #replace all other occurrences
Push all #replace all other occurrences
Push C:\temp1.bat #file to replace in
Push C:\temp1.bat #file to replace in
Line 31: Line 63:
Push all #replace all occurrences
Push all #replace all occurrences
Push all #replace all occurrences
Push all #replace all occurrences
Push C:\temp1.bat #file to replace in
Push 'C:\Program Files\temp1.info' #file to replace in
  Call AdvReplaceInFile
  Call AdvReplaceInFile
</highlight-nsis>
</highlight-nsis>


== The Function ==
== Code ==
<highlight-nsis>
<highlight-nsis>
/*
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
Function AdvReplaceInFile
Exch $0 ;file to replace in
Exch $0 ;FILE_TO_MODIFIED file to replace in
Exch
Exch
Exch $1 ;number to replace after
Exch $1 ;the NR_OCC of OLD_STR occurrences to be replaced.
Exch
Exch
Exch 2
Exch 2
Exch $2 ;replace and onwards
Exch $2 ;FST_OCC: the first occurrence to be replaced and onwards
Exch 2
Exch 2
Exch 3
Exch 3
Exch $3 ;replace with
Exch $3 ;REPLACEMENT_STR string to replace with
Exch 3
Exch 3
Exch 4
Exch 4
Exch $4 ;to replace
Exch $4 ;OLD_STR to be replaced
Exch 4
Exch 4
Push $5 ;minus count
Push $5 ;incrementing counter
Push $6 ;universal
Push $6 ;a chunk of read line
Push $7 ;end string
Push $7 ;the read line altered or not
Push $8 ;left string
Push $8 ;left string
Push $9 ;right string
Push $9 ;right string or forster read line
Push $R0 ;file1
Push $R0 ;temp file handle
Push $R1 ;file2
Push $R1 ;FILE_TO_MODIFIED file handle
Push $R2 ;read
Push $R2 ;a line read
Push $R3 ;universal
Push $R3 ;the length of OLD_STR
Push $R4 ;count (onwards)
Push $R4 ;counts reaching of FST_OCC
Push $R5 ;count (after)
Push $R5 ;counts reaching of NR_OCC
Push $R6 ;temp file name
Push $R6 ;temp file name


   GetTempFileName $R6
   GetTempFileName $R6
   FileOpen $R1 $0 r ;file to search in
 
   FileOpen $R0 $R6 w ;temp file
   FileOpen $R1 $0 r ;FILE_TO_MODIFIED file to search in
   StrLen $R3 $4
   FileOpen $R0 $R6 w                   ;temp file
   StrCpy $R4 -1
   StrLen $R3 $4 ;the length of OLD_STR
   StrCpy $R5 -1
   StrCpy $R4 0 ;counter initialization
 
   StrCpy $R5 -1 ;counter initialization
loop_read:
loop_read:
  ClearErrors
  ClearErrors
  FileRead $R1 $R2 ;read line
  FileRead $R1 $R2 ;reading line
  IfErrors exit
  IfErrors exit ;when end of file has been reached
 
   StrCpy $5 0
   StrCpy $5 -1  ;cursor, start of read line chunk
   StrCpy $7 $R2
  StrLen $7 $R2 ;read line length
 
  IntOp $5 $5 - $7 ;cursor initialization
   StrCpy $7 $R2 ;$7 contains read line
loop_filter:
loop_filter:
   IntOp $5 $5 - 1
   IntOp $5 $5 + 1 ;cursor shifting
   StrCpy $6 $7 $R3 $5 ;search
  StrCmp $5 0 file_write ;end of line has been reached
  StrCmp $6 "" file_write1
   StrCpy $6 $7 $R3 $5 ;a chunk of read line of length OLD_STR
   StrCmp $6 $4 0 loop_filter
   StrCmp $6 $4 0 loop_filter ;continues to search OLD_STR if no match
 
StrCpy $8 $7 $5 ;left part
StrCpy $8 $7 $5 ;left part  
IntOp $6 $5 + $R3
IntOp $6 $5 + $R3
IntCmp $6 0 is0 not0
IntCmp $6 0 yes no ;left part + OLD_STR == full line read ?
is0:
yes:
StrCpy $9 ""
StrCpy $9 ""
Goto done
Goto done
not0:
no:
StrCpy $9 $7 "" $6 ;right part
StrCpy $9 $7 "" $6 ;right part
done:
done:
StrCpy $7 $8$3$9 ;re-join
StrCpy $9 $8$3$9 ;replacing OLD_STR by REPLACEMENT_STR in forster read line


IntOp $R4 $R4 + 1
IntOp $R4 $R4 + 1 ;counter incrementation
StrCmp $2 all loop_filter
;MessageBox MB_OK|MB_ICONINFORMATION \
StrCmp $R4 $2 0 file_write2
;"count R4 = $R4, fst_occ = $2"
IntOp $R4 $R4 - 1
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


IntOp $R5 $R5 + 1
follow_up:
StrCmp $1 all loop_filter
IntOp $R4 $R4 - 1 ;now counter is to be stuck to FST_OCC
StrCmp $R5 $1 0 file_write1
IntOp $R5 $R5 - 1
IntOp $R5 $R5 + 1 ;counter incrementation
Goto file_write2
;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


file_write1:
exchange_ok:
FileWrite $R0 $7 ;write modified line
IntOp $5 $5 + $R3 ;updating cursor
Goto loop_read
StrCpy $7 $9 ;updating read line with forster read line
Goto loop_filter ;goes searching the same read line


file_write2:
finalize:
FileWrite $R0 $R2 ;write unmodified line
IntOp $R5 $R5 - 1 ;now counter is to be stuck to NR_OCC
Goto loop_read


file_write:
FileWrite $R0 $7 ;writes altered or unaltered line
Goto loop_read ;reads the next line
exit:
exit:
   FileClose $R0
   FileClose $R0
   FileClose $R1
   FileClose $R1
 
   SetDetailsPrint none
   ;SetDetailsPrint none
   Delete $0
   Delete $0
   Rename $R6 $0
   Rename $R6 $0 ;superseding FILE_TO_MODIFIED file with
   Delete $R6
;temp file built with REPLACEMENT_STR
   SetDetailsPrint lastused
   ;Delete $R6
 
   ;SetDetailsPrint lastused
Pop $R6
Pop $R6
Pop $R5
Pop $R5
Line 147: Line 227:


== Versions History ==
== 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
; 2010-10-09
: Bug fixed that doesn't change "all" occurrences
: Bug fixed that doesn't change "all" occurrences

Latest revision as of 17:45, 14 December 2020

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)