fbpx
Welcome, Guest
Username: Password: Remember me
  • Page:
  • 1

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

Best/Simplest way to replace lines of text in a file 1 month 1 week ago #13276

  FFF's Avatar Topic Author FFF Offline Posts: 852
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:
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!
Regards
Karl (X# 2.3b; Xide 1.24; W8.1/64 German)

Please Log in or Create an account to join the conversation.

Best/Simplest way to replace lines of text in a file 1 month 1 week ago #13286

  Chris's Avatar Chris Offline Posts: 1745
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?
XSharp Development Team
chris(at)xsharp.eu

Please Log in or Create an account to join the conversation.

Best/Simplest way to replace lines of text in a file 1 month 1 week ago #13287

  Terry's Avatar Terry Offline Posts: 163
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

Please Log in or Create an account to join the conversation.

Best/Simplest way to replace lines of text in a file 1 month 1 week ago #13288

  Kevin Clark's Avatar Kevin Clark Offline Posts: 47
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.

Please Log in or Create an account to join the conversation.

Best/Simplest way to replace lines of text in a file 1 month 1 week ago #13289

  FFF's Avatar Topic Author FFF Offline Posts: 852
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?
Regards
Karl (X# 2.3b; Xide 1.24; W8.1/64 German)

Please Log in or Create an account to join the conversation.

Last edit: by FFF.

Best/Simplest way to replace lines of text in a file 1 month 1 week ago #13291

  Chris's Avatar Chris Offline Posts: 1745
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?
XSharp Development Team
chris(at)xsharp.eu

Please Log in or Create an account to join the conversation.

Best/Simplest way to replace lines of text in a file 1 month 1 week ago #13293

  FFF's Avatar Topic Author FFF Offline Posts: 852
Chris,
nothing not to like, simply no clue ;)
Anyway, following Kevin's/your suggestion:
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:
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 ;)
Regards
Karl (X# 2.3b; Xide 1.24; W8.1/64 German)

Please Log in or Create an account to join the conversation.

Last edit: by FFF.

Best/Simplest way to replace lines of text in a file 1 month 1 week ago #13305

  Kevin Clark's Avatar Kevin Clark Offline Posts: 47
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

Please Log in or Create an account to join the conversation.

Last edit: by Kevin Clark.

Best/Simplest way to replace lines of text in a file 1 month 1 week ago #13310

  FFF's Avatar Topic Author FFF Offline Posts: 852

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 ;)
Regards
Karl (X# 2.3b; Xide 1.24; W8.1/64 German)

Please Log in or Create an account to join the conversation.

Best/Simplest way to replace lines of text in a file 1 month 1 week ago #13311

  Kevin Clark's Avatar Kevin Clark Offline Posts: 47
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.

Please Log in or Create an account to join the conversation.

Best/Simplest way to replace lines of text in a file 1 month 1 week ago #13312

  FFF's Avatar Topic Author FFF Offline Posts: 852
Hm.
FUNCTION Start( ) AS VOID
	LOCAL array1[2]
	array1[1 ]:="Old line 1"
	array1[2]:="Old line 2"
	FOREACH cArrayLine AS STRING IN array1
		cArrayLine:="This is a new line"
		? cArrayLine
	NEXT
RETURN
warning XS9064: Cannot assign to 'cArrayLine' because it is a 'foreach iteration variable'
Using X#/FoxPro in Xide
Looking back to my code i recognise, you are right, also in X#/VO i see "only" a warning...

BUT: Adding a "? array1[1]" AFTER your "NEXT" - i see again "Old line 1" !!

@Dev: I don't understand, why you issue only a warning here - "Cannot" != "Should not" ;)
Regards
Karl (X# 2.3b; Xide 1.24; W8.1/64 German)

Please Log in or Create an account to join the conversation.

Last edit: by FFF.

Best/Simplest way to replace lines of text in a file 1 month 1 week ago #13314

  Kevin Clark's Avatar Kevin Clark Offline Posts: 47
You're right. That does issue a warning. I didn't notice it because it compiled and ran so fast I couldn't read the warning before it was gone. But if I set "Warnings as Errors" then it stops and shows the warning and won't compile.

Regarding the original array not changing, it looks like FOR EACH is creating a new variable rather than a reference to the original variable. (FYI I tried it in Foxpro and it did the same thing.) With that in mind, it would clearly be better to use a FOR ... NEXT with a counter and process directly each array element, as you had in your other example.

Please Log in or Create an account to join the conversation.

Last edit: by Kevin Clark.

Best/Simplest way to replace lines of text in a file 1 month 1 week ago #13316

  Chris's Avatar Chris Offline Posts: 1745
Karl,

FFF wrote: @Dev: I don't understand, why you issue only a warning here - "Cannot" != "Should not" ;)


This is an error message that c# uses, so X# uses the same one. In c#, modifying the iteration variable is never allowed, but since there's no fundamental real problem when actually doing so, and because vulcan did allow it, we made it a warning in X#, instead of an error (and the same has happened with literally dozens of other c# errors!).

But I agree, it should be better to slightly adjust the message itself.
XSharp Development Team
chris(at)xsharp.eu

Please Log in or Create an account to join the conversation.

Best/Simplest way to replace lines of text in a file 1 month 1 week ago #13321

  Kevin Clark's Avatar Kevin Clark Offline Posts: 47
Chris, when the items being iterated are more formally objects (rather than say a string or integer), I'm assuming that properties of the iteration variable can be changed. For example, my main application has students and courses. So, in a case like this:
For each course in student.courselist
     course.startdate=date()
next
I'm assuming that the above code would change the actual object in student.courselist rather than creating a new course object. Is that correct?

Please Log in or Create an account to join the conversation.

Last edit: by Kevin Clark.

Best/Simplest way to replace lines of text in a file 1 month 1 week ago #13324

  Chris's Avatar Chris Offline Posts: 1745
Kevin, the quick answer would be "yes", but it actually depends on the type of the elements in the collection. If the elements are of a "reference type" (class), then what you get is a var that points (has a reference) to the (each) original element. But if you have a collection of "value type" (structure), then the foreach var only contains a copy of the original element.

So for a List<System.Windows.Forms.Control>, the iteration var of foreach would point to each actual element every time, and modifying a property on it will modify the property in the original element. But for a List<System.Drawing.Point>, the iteration var would only receive a copy of the original element and modifying a property of the var would only affect that local copy.

Maybe this is the reason why it's not allowed in c# to modify the iteration var, because of this possible confusion it could create with reference vs value types.
XSharp Development Team
chris(at)xsharp.eu

Please Log in or Create an account to join the conversation.

  • Page:
  • 1