Archive: How to Remove Or Replace Characters 11 Through 29 & 1 Through 9 On All Lines?


How to Remove Or Replace Characters 11 Through 29 & 1 Through 9 On All Lines?
I've got an extremely long text file and I only need to remove characters at certain positions on all lines. e.g. I am trying to close in on the tenth character so I need to remove characters 11 through 29 & 1 through 9 and I need to do this for all lines.

0002020107001010201010101020230201010201 SHEEP and 7 WOLVES
^
In the end, the above code should look like the following.
7 SHEEP and 7 WOLVES
Heres the catch. I've already accomplished this and it works perfectly BUT the process takes a very long 10 minutes on 800+ lines.

The only method I know on how to accomplish this is to:

1. open the file
2. scan the entire file
3. replace each line only once per scan
4. close file
5. repeat steps 1 through 4 800x

Can someone please optimize this savaged attempt with a Function that easily replaces x to n on all lines?

Thank you!

vbgunz, I wrote the following (using Afrow UK's Read from text file line number function), and tested it on a text file (text.txt) that consisted of 800 lines of:

00020201070010102010101010202 SHEEP and 7 WOLVES
00020201070010102010101010202 SHEEP and 7 WOLVES
00020201070010102010101010202 SHEEP and 7 WOLVES
00020201070010102010101010202 SHEEP and 7 WOLVES
etc...

It created a new text file called text1.txt in 15 seconds consisting of 800 lines of:

7 SHEEP and 7 WOLVES
7 SHEEP and 7 WOLVES
7 SHEEP and 7 WOLVES
etc...

Once you have the new text file (text1.txt) you can copy it back over you original, or do with it as you please. Here is the code. Note you should only have to change the text file names and the end number (801). Hope this helps.


!include "MUI.nsh"
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"

; MUI end ------

OutFile "Setup.exe"
ShowInstDetails show

Section "MainSection" SEC01

StrCpy $1 0
Loop:
Intop $1 $1 + 1 ;Sets line number to be read below
StrCmp $1 801 End

Push $1 ;line number to read from
Push "text.txt" ;text file to read
Call ReadFileLine
Pop $0 ;output string (read from file.txt)

StrCpy $2 $0 "" 9 ;sets $2 = line $1 minus first 9 characters
StrCpy $3 $2 1 ;sets $3 to first character of $2
StrCpy $4 $2 "" 20 ;sets $4 = line $1 minus everything before character 30

FileOpen $5 Text1.txt a
FileSeek $5 0 END
FileWrite $5 $3
FileWrite $5 $4
FileClose $5
Goto Loop

End:
SectionEnd



Function ReadFileLine
Exch $0 ;file
Exch
Exch $1 ;line number
Push $2
Push $3

FileOpen $2 $0 r
StrCpy $3 0

Loop:
IntOp $3 $3 + 1
ClearErrors
FileRead $2 $0
IfErrors +2
StrCmp $3 $1 0 loop
FileClose $2

Pop $3
Pop $2
Pop $1
Exch $0
FunctionEnd

First off, I'd like to say, Major Thanks! You've created the code with a lof of room for tweaks and I love it. I am enjoying it's flexibiliy and hope you publish this on the archive for others... (strange no one ever asked for this).

Jnuw, If possible can you please show me a method that will sort of do exactly what it is you do now with the code BUT write something onto the end of every line?

e.g. 7 SHEEP and 7 WOLVES!!!

How would I go about adding exclamation marks onto the end of every line?

Believe this or not you've already jumped me way ahead of myself. Help me with this last piece and the puzzles complete. I'd have nothing but major thanks for you all over the spot :)

Thank you again for your help!


Name "Output"
OutFile "Output.exe"

!include "TextFunc.nsh"
!insertmacro LineFind
!insertmacro TrimNewLines

Section
${LineFind} "C:\input.txt" "C:\output.txt" "1:-1" "LineFindCallback"

IfErrors 0 +2
MessageBox MB_OK "Error"
SectionEnd

Function LineFindCallback
${TrimNewLines} '$R9' $R9
StrCpy $1 $R9 1 9
StrCpy $R9 $R9 '' 29
StrCpy $R9 '$1$R9!!!$\r$\n'

Push $0
FunctionEnd


It created a new text file in 1 second consisting of 8000 lines of :)

Script used header

OMG. That truly is amazing. Jnuw, thank you so much for helping me out, it's always priceless, appreciated and respected! You're trick was way better than mines 100 fold. Thanks again!

Instructor, that really was incredible! I never thought my text files would get processed so fast. man thats good ;) I have just one question which has really nothing to do with what you just provided as it is perfect.

My question is in regards to your "FileReadFromEnd v1.1 part 1.nsi" in which I am trying to use in conjunction with my current project. It seems every time I run that function it tends to append the second to last line onto the end of the last line BEFORE it actually reverses the files contents. I can't seem to work around it... Would you know why this might happen?


It seems every time I run that function it tends to append the second to last line onto the end of the last line BEFORE it actually reverses the files contents.
ou man it's so hard to read with my English :) Can you say it with other words (the best way with examples)

I'll try to explain it :)

This is what the file looks like before it gets reversed.

1. a
2. a
3. a
4. a
5. a
6. a
7. a
8. a
9. a

This is what it looks like after it get reversed.

9. a8. a
7. a
6. a
5. a
4. a
3. a
2. a
1. a

This happens to the newly created file. If it helps I am using "example 2" but I have slightly modified it as so

      GetTempFileName $R0
FileOpen $R1 $R0 w
${FileReadFromEnd} "$EXEDIR\test.txt" "WriteReverse"
FileClose $R1
Delete $R1
CopyFiles $R0 "$EXEDIR\test.txt"
Thanks Instructor!

Yes, I know about it. It's because last line "9. a" have not $\r or $\n at the and of line. I thought when writing function add these characters if missed but decided to output lines as is. I add some lines in example2. Thanks, vbgunz.

Name "Output"
OutFile "Output.exe"

!include "TextFunc.nsh"
!insertmacro FileReadFromEnd


###Example2 (Reverse text file):
Section
GetTempFileName $R0
FileOpen $R1 $R0 w
${FileReadFromEnd} "C:\input.txt" "Example2"
FileClose $R1

IfErrors 0 +2
MessageBox MB_OK "Error" IDOK +2
Exec '"notepad.exe" "$R0"'
SectionEnd

Function Example2
StrCmp $7 -1 0 +5
StrCpy $1 $9 1 -1
StrCmp $1 '$\n' +3
StrCmp $1 '$\r' +2
StrCpy $9 '$9$\r$\n'

FileWrite $R1 "$9"

Push $0
FunctionEnd


PS:
Why you need this line in code? :)
Delete $R1
try to use /SILENT flag for CopyFiles if you copy just text file (faster)

Major Thanks Instructor! Everything you've written so far is perfect. About my bumble with Delete $R1... Well, I actually forgot why I was using it... I think it belonged to experimental code as I pulled it from a testbed script.

Wow, in the end instructor, I've managed to piece together a perfect parser for my job with 99% thanks to you. Most of the functions and stuff I've scraped together to make it work all have your name on it ;)

Anyhow, I owe you for last time and I promise to try and get your work into the archive when time permits. Right now I am dead beat and am about to go to bed... I got to say though my dreams will be sweeet!

Thanks again!


I just remembered why I was using Delete $R1. If I don't delete $R1 (source file) the copy will fail.

Thanks again!


Originally posted by Instructor
It created a new text file in 1 second consisting of 8000 lines of :)
Very nice! :up:

Instructor, I hope you get this message. Utilizing your work, I've managed to create a perfect runtime parser for my project. Unfortunately, I actually need it to perform during compile time. How would you convert the following runtime code to compiletime code?

Name "Output"
OutFile "Output.exe"

!include "TextFunc.nsh"
!insertmacro LineFind
!insertmacro TrimNewLines

Function FileReadFromEnd
!define FileReadFromEnd `!insertmacro FileReadFromEndCall`

!macro FileReadFromEndCall _FILE _FUNC
Push $0
Push `${_FILE}`
GetFunctionAddress $0 `${_FUNC}`
Push `$0`
Call FileReadFromEnd
Pop $0
!macroend

Exch $1
Exch
Exch $0
Exch
Push $7
Push $8
Push $9
ClearErrors

StrCpy $7 -1
StrCpy $8 0
IfFileExists $0 0 error
FileOpen $0 $0 r
IfErrors end
FileRead $0 $9
IfErrors +4
Push $9
IntOp $8 $8 + 1
goto -4
FileClose $0

nextline:
StrCmp $8 0 end
Pop $9
Push $1
Push $7
Push $8
Call $1
Pop $0
Pop $8
Pop $7
Pop $1
IntOp $7 $7 - 1
IntOp $8 $8 - 1
IfErrors error
StrCmp $0 'StopFileReadFromEnd' clearstack nextline

error:
SetErrors

clearstack:
StrCmp $8 0 end
Pop $9
IntOp $8 $8 - 1
StrCmp $8 0 0 -2

end:
Pop $9
Pop $8
Pop $7
Pop $1
Pop $0
FunctionEnd

Function WriteReverse
StrCmp $7 -1 0 +5
StrCpy $1 $9 1 -1
StrCmp $1 '$\n' +3
StrCmp $1 '$\r' +2
StrCpy $9 '$9$\r$\n'

FileWrite $R1 "$9"
Push $0
FunctionEnd

Section
;--------------------------------------------------------------------------------------------------
GetTempFileName $R0
FileOpen $R1 $R0 w
${FileReadFromEnd} "$EXEDIR\text.txt" "WriteReverse"
FileClose $R1
;--------------------------------------------------------------------------------------------------
${LineFind} "$R0" "$EXEDIR\text.txt.log" "1:-1" "LineFindCallback"
SectionEnd

Function LineFindCallback
${TrimNewLines} '$R9' $R9
StrCpy $1 $R9 1 20
StrCpy $R9 $R9 '' 56
;--------------------------------------------------------------------------------------------------
StrCmp $1 "D" 0 isFile
StrCpy $R9 'RMDir $\"$$INSTDIR\$R9$\"$\r$\n'

Goto skipahead
isFile:
StrCpy $R9 'Delete /REBOOTOK $\"$$INSTDIR\$R9$\"$\r$\n'
skipahead:
;--------------------------------------------------------------------------------------------------
Push $0
FunctionEnd
I really don't know how to extend my thanks for your time so I wish to assure you I am very grateful. Thank you again Instructor!

It's easy to use:

!include "TextFunc.nsh"
!insertmacro LineFind
!insertmacro TrimNewLines
!insertmacro FileReadFromEnd


In place of big include:
Function FileReadFromEnd
;...
FunctionEnd

Man I feel like a bubble head. You say it's easy to get all that runtime code I posted to turn into compiletime code by simply placing an insertmacro... I am running into doozies... e.g.

Error: can't define a macro inside a macro!


It seems your solution at a glance will only work with FileReadFromEnd so I assume I must take the other functions and turn them into !macros. On top of that... The little piece of code I have in the section... I should also place this in a !macro?

Thank you!

"TextFunc.nsh" allready contain FileReadFromEnd function. All you need is put function in code "!insertmacro FileReadFromEnd" (if you didn't modifity "TextFunc.nsh" :) )

Name "Output"
OutFile "Output.exe"

!include "TextFunc.nsh"
!insertmacro LineFind
!insertmacro TrimNewLines
!insertmacro FileReadFromEnd

Function WriteReverse
StrCmp $7 -1 0 +5
StrCpy $1 $9 1 -1
StrCmp $1 '$\n' +3
StrCmp $1 '$\r' +2
StrCpy $9 '$9$\r$\n'

FileWrite $R1 "$9"
Push $0
FunctionEnd

Section
;--------------------------------------------------------------------------------------------------
GetTempFileName $R0
FileOpen $R1 $R0 w
${FileReadFromEnd} "$EXEDIR\text.txt" "WriteReverse"
FileClose $R1
;--------------------------------------------------------------------------------------------------
${LineFind} "$R0" "$EXEDIR\text.txt.log" "1:-1" "LineFindCallback"
SectionEnd

Function LineFindCallback
${TrimNewLines} '$R9' $R9
StrCpy $1 $R9 1 20
StrCpy $R9 $R9 '' 56
;--------------------------------------------------------------------------------------------------
StrCmp $1 "D" 0 isFile
StrCpy $R9 'RMDir $\"$$INSTDIR\$R9$\"$\r$\n'

Goto skipahead
isFile:
StrCpy $R9 'Delete /REBOOTOK $\"$$INSTDIR\$R9$\"$\r$\n'
skipahead:
;--------------------------------------------------------------------------------------------------
Push $0
FunctionEnd

I was having some problems and realized I should check for the latest headers. That solved my first problem. My second problem (hopefully the last), is the code is still runtime only.

I am trying to make this code parse a page at compile time. I need to do something with the parsed file before I finish building the installer. This I was hoping you can help me out on.

I have not modified TextFunc in any way. The only code I am modifying is the code in which you've pasted back into this thread... That's about the only code I am working with hands on.

I hope you understand. Thanks Instructor!


http://nsis.sourceforge.net/archive/...instances=0,44

-Stu


Afrow, I found that link first before ever asking for help on this. The reason I decided to ask, is I have no idea how to implement that script into what I need it for :(

I think I need a better example as I was dazed out and confused just pondering "how do I implement it". Can you provide a different example on something much simpler?


Thanks for the help Afrow, I basically solved it and converted the runtime code into compile time BUT if possible I would still like to see an easier example regarding your code.

Thanks again!


I added some more notes, but it can't really get much easier than that. What would you suggest?

-Stu


I am trying to make this code parse a page at compile time. I need to do something with the parsed file before I finish building the installer. This I was hoping you can help me out on.
The only way I see it's create single exe and hand needfull parameters by CMDLINE (Call this single exe with !execute)

Instructor, that is exactly what I did ;) Afrow, I will take a look at your new example as I did wish to use it :)

Thanks Fellas!