xsharp.eu • Best/Simplest way to replace lines of text in a file
Page 1 of 2

Best/Simplest way to replace lines of text in a file

Posted: Mon Feb 17, 2020 3:03 pm
by FFF
Feeling a bit like Jeff, as it's a dummy question:
I read files from a directory, select some of them, replace some lines in each file with some other text and write the modified content to a new file.
Starts like this:

Code: Select all

	oInfo:=Directoryinfo{cPfad}
	aFiles:=oInfo:GetFiles("*.s4w")
	FOREACH x AS  FileInfo IN aFiles
		oSource := Streamreader{x:FullName}
		DO WHILE .not. oSource:EndOfStream
			cLine:=oSource:ReadLine()
			IF cLine:Contains("NA=")  .and. cLine:Length > 4 
				? cLine:Replace(cS4P_Dolli, cPfad_S4P)
			ENDIF
		END DO
Works, and the relevant cLine is changed as it should.
But now on i feel like there are to many possibilites to proceed ;)

Any hint welcomed!

Best/Simplest way to replace lines of text in a file

Posted: Mon Feb 17, 2020 6:31 pm
by Chris
Hi Karl,

Do you mean, how to write the data back on disk? I'd say simply create a StreamWriter and write to it line by line, after you make the necessary adjustments to each one. Or did you mean something else?

Best/Simplest way to replace lines of text in a file

Posted: Mon Feb 17, 2020 6:31 pm
by TerryB1
Karl

No, it's not a dummy question.

I don't know enough about X# language syntax to comment on the code. But what are you trying to do overall?

I assume you are trying to perform some sort of textual transformation. Probably complex. Thousands of alternatives - most of which you want to exclude. If this is not the case then please ignore the following.

1 Whenever you have too many possible alternatives to address, try and think the reverse way: Could you, more easily, identify the alternatives you DON'T want, then negate the result?

2 When reading and writing to a file you are creating quite a time consuming processing overhead. Would it be better to do it all via Lists or Arrays.

3 Data Structures have a significant part to play in respect of performance: Try searching web for Rope Data Structures.

Hope that helps a bit - there's more to this than hits the eye.

Terry

Best/Simplest way to replace lines of text in a file

Posted: Mon Feb 17, 2020 7:53 pm
by kevclark64
You'd have to test it, but it seems like it would have to be faster to read the whole file first, do the processing you want, then write the whole file back at once.

Best/Simplest way to replace lines of text in a file

Posted: Mon Feb 17, 2020 8:18 pm
by FFF
Terry,
thanks, but it IS dump... I'm way lower in my coding ambitions - nothing "big data", only some files in a folder to handle ;)
@Chris: yes, that describes it. As you see in my code, i already "have" the modified data in the streamreader, so i thought, one might feed that into a writer. But following the docs this seems not to be the way to do it...
(Sorry, i code so seldom these days i way faster forget than i have learned...)

@Kevin: i "think", that's what i did with the StreamReader?

Best/Simplest way to replace lines of text in a file

Posted: Mon Feb 17, 2020 8:45 pm
by Chris
Hi Karl,

Either do as Kevin said, load everything in an array (File.ReadAllLines()), manipulate it and write back with File.WriteAllLines(), or if you want to just adjust the above code, create a StreamWriter and use oStreamWriter:WriteLine() for each line. Not sure what you don't like about this, can you please explain a bit more?

Best/Simplest way to replace lines of text in a file

Posted: Mon Feb 17, 2020 9:47 pm
by FFF
Chris,
nothing not to like, simply no clue ;)
Anyway, following Kevin's/your suggestion:

Code: Select all

	FOREACH x AS  FileInfo IN aFiles
		VAR NewFileName :=Path.GetFileNameWithoutExtension(x:FullName)
		VAR NewFullFilename := x:DirectoryName+  NewFileName + "_a" +  x:Extension
		VAR acLines := File.ReadAllLines(x:Fullname)
		FOREACH cLine AS  STRING IN acLines
			IF cLine:Contains("NA=")  .and. cLine:Length > 4 
				? cLine
				? cLine:Replace(cS4P_Dolli, cPfad_S4P)
			ENDIF
		NEXT
		File.WriteAllLines(NewFullFilename, acLines)
	NEXT
Works, as it changes the content of some of the lines and creates a copy of the sourcefile with modified name.
ONLY one fault, the modified lines don't make it into the new file, there i find the old ones.
?
Thx for your patience
EDIT: Found it. The "inmutable" string thing got me - i.e. after the ? cLine:Replace() this result gets dropped.
So:

Code: Select all

FOREACH x AS  FileInfo IN aFiles
		VAR NewFileName :=Path.GetFileNameWithoutExtension(x:FullName)
		VAR NewFullFilename := x:DirectoryName+  NewFileName + "_a" +  x:Extension
		VAR acLines := File.ReadAllLines(x:Fullname)

		FOR VAR i := 1 UPTO acLines:Length
			IF acLines[i]:Contains("NA=")  .and. acLines[i]:Length > 4 
				VAR cNewLine:= acLines[i]:Replace(cS4P_Dolli, cPfad_S4P)
				acLines[i]:= cNewLine
			ENDIF
		NEXT
		File.WriteAllLines(NewFullFilename, acLines)
	NEXT
RETURN   TRUE
Works as it should. Note: Verrry sloppy code, not to be copied without adding necessary exeption handling etc. For me (that's the usual excuse) it suffices, as i'll have to use it in exactly one place maybe 5 times a year ;)

Best/Simplest way to replace lines of text in a file

Posted: Tue Feb 18, 2020 3:18 pm
by kevclark64
I think your first version should work if you replace:
? cLine
? cLine:Replace(cS4P_Dolli, cPfad_S4P)
with:
? cLine
cLine:=cLine:Replace(cS4P_Dolli, cPfad_S4P)
? cLine

Best/Simplest way to replace lines of text in a file

Posted: Tue Feb 18, 2020 8:13 pm
by FFF
Kevin Clark wrote:I think your first version should work if you replace:
cLine:=cLine:Replace(cS4P_Dolli, cPfad_S4P)
Gave it a try, but the line does not compile:
XS9064: Cannot assign to 'cLine' because it is a 'foreach iteration variable'

Thx for trying ;)

Best/Simplest way to replace lines of text in a file

Posted: Tue Feb 18, 2020 8:52 pm
by kevclark64
Interesting that wouldn't compile. I tried the following, which is doing basically the same thing you are doing, and it worked:

local array1[2]
array1[1]="Old line 1"
array1[2]="Old line 2"
FOR EACH cArrayLine as String IN array1
cArrayLine="This is a new line"
? cArrayLine
NEXT

The above is in the Foxpro dialect so maybe that makes a difference, but the beauty of using FOR EACH is that it makes it easier to manipulate each variable or object within an array or collection. Not being able to modify the resulting variable or object would sort of defeat the purpose.