More advanced replace text in file: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
Line 36: Line 36:
</highlight-nsis>
</highlight-nsis>


== The Function ==
/*
<highlight-nsis>
First occurrence to be replaced: FST_OCC. FST_OCC = all, is the same as FST_OCC = 1.
  if FST_OCC greater than the number of occurences: no alteration of the file
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 = integer, replaces up to NR_OCC occurrences provided they exist 
NR_OCC, FST_OCC negative will yield the same result as NR_OCC, FST_OCC equal to all.
 
Order to run down and search the file: from left to right and top down.
REPLACEMENT_STR, OLD_STR should be less than 1024 characters long.
*/
 
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}" ; start replacing after FST_OCC occurrences
Push "${NR_OCC}" ; replace 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 $R1 $0 r ;FILE_TO_MODIFIED file to search in
   FileOpen $R0 $R6 w ;temp file
   FileOpen $R0 $R6 w ;temp file
   StrLen $R3 $4
   StrLen $R3 $4 ;the length of OLD_STR
   StrCpy $R4 -1
   StrCpy $R4 0 ;counter initialization
   StrCpy $R5 -1
   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 ;reading 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 searching 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 4 = $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 5 = $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 counter
Goto loop_read
StrCpy $7 $9 ;updating line read 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 145: Line 188:
Pop $4
Pop $4
FunctionEnd
FunctionEnd
</highlight-nsis>


== Versions History ==
== Versions History ==

Revision as of 20:24, 11 December 2020

Author: Afrow UK (talk, contrib)


Description

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. Just copy the full code underneath in a file named: ReplaceInFile3.nsh and save it in the Include folder of your NSIS installation folder.

Usage 1

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

Usage 2

Push hello #text to be replaced
Push blah #replace with
Push 3 #start replacing after 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:\temp1.bat #file to replace in
 Call AdvReplaceInFile

/* First occurrence to be replaced: FST_OCC. FST_OCC = all, is the same as FST_OCC = 1.

  if FST_OCC greater than the number of occurences: no alteration of the file

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 = integer, replaces up to NR_OCC occurrences provided they exist   

NR_OCC, FST_OCC negative will yield the same result as NR_OCC, FST_OCC equal to all.

Order to run down and search the file: from left to right and top down. REPLACEMENT_STR, OLD_STR should be less than 1024 characters long.

  • /

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}" ; start replacing after FST_OCC occurrences Push "${NR_OCC}" ; replace 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 			;reading 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 searching 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 4 = $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 5 = $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 counter StrCpy $7 $9 ;updating line read 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

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)