why writing the file is partial

L

Li Chen

Hi all,

Thank you for your valuable inputs for my previous post.

Right now I encounter another odd situation. I want to search some
strings and replace them all in place. ButI can partially update/replace
part of them. I wonder if any experts there can explain it.

Li

And here are my codes:

my_direrctory="C:\\flow\\test"

pat=/2\.000000\\\$P1G\\2\.000000/
sub='1.000000\$P1G\\\1.000000'

Dir.chdir(my_direrctory)
Dir.foreach(my_direrctory) do |filename| #return a file name
next if filename=~/^\./ # skip . and ..
my_file_path=my_direrctory+"\\"+filename #get absolute file name
File.open( my_file_path,"r+") do |file| #pass a file to the block
file.each_line do |line|
if pat.match(line)
line.gsub!(pat,sub) #replace the line in place
file.print line #write/update the file
end
end
end
end

#####input file format###
test.001
xxx\2.000000\$P1G\2.000000\xxx
xxx\2.000000\$P1G\2.000000\xxx
xxx\2.000000\$P1G\2.000000\xxx
xxx\2.000000\$P1G\2.000000\xxx


### the updated file###
test.001
xxx\2.000000\$P1G\2.000000\xxx
xxx\1.000000\$P1G\1.000000\xxx
xxx\2.000000\$P1G\2.000000\xxx
xxx\1.000000\$P1G\1.000000\xxx
 
R

Robert Klemme

Hi all,

Thank you for your valuable inputs for my previous post.

Right now I encounter another odd situation. I want to search some
strings and replace them all in place. ButI can partially update/replace
part of them. I wonder if any experts there can explain it.

Li

And here are my codes:

my_direrctory="C:\\flow\\test"

pat=/2\.000000\\\$P1G\\2\.000000/
sub='1.000000\$P1G\\\1.000000'

Dir.chdir(my_direrctory)
Dir.foreach(my_direrctory) do |filename| #return a file name
next if filename=~/^\./ # skip . and ..
my_file_path=my_direrctory+"\\"+filename #get absolute file name
File.open( my_file_path,"r+") do |file| #pass a file to the block
file.each_line do |line|
if pat.match(line)
line.gsub!(pat,sub) #replace the line in place
file.print line #write/update the file
end
end
end
end

#####input file format###
test.001
xxx\2.000000\$P1G\2.000000\xxx
xxx\2.000000\$P1G\2.000000\xxx
xxx\2.000000\$P1G\2.000000\xxx
xxx\2.000000\$P1G\2.000000\xxx


### the updated file###
test.001
xxx\2.000000\$P1G\2.000000\xxx
xxx\1.000000\$P1G\1.000000\xxx
xxx\2.000000\$P1G\2.000000\xxx
xxx\1.000000\$P1G\1.000000\xxx

Reading and writing one file at the time is a dangerous thing to do -
especially if pattern and replacement can have different lengths. If
you want to do it properly, then you need to #seek before you switch
from reading to writing and back AFAIK. But I'd use a temporary file,
this is much safer. Then you can even do it in a one liner:

ruby -i.bak -pe 'gsub /pattern/, "replacement"' your_file1 your_file2

Kind regards

robert
 
R

Rick DeNatale

On 13.06.2007 18:58, Li Chen wrote:

Reading and writing one file at the time is a dangerous thing to do -
especially if pattern and replacement can have different lengths. If
you want to do it properly, then you need to #seek before you switch
from reading to writing and back AFAIK.

Right, I think what's happening here is that he reads the first line,
the file cursor is positioned after the first line, so he overwrites
the SECOND line with the updated first line, and is now positioned at
the end of the second line, etc. etc.

He needs to seek back to the beginning of the line before he writes:

file.each_line do |line|
if pat.match(line)
line.gsub!(pat,sub) #replace the line in place
file.seek(-line.length, IO::SEEK_CUR)
file.print line #write/update the file
end
end
end

But this will only work in the case where the replacement is the same
length at the original, if you you're either going to leave stuff
behind, or will overwrite the next line. In either case you're more
likely to end up with gibberish than something you like.
But I'd use a temporary file,
this is much safer.

Amen, and it will preserve the original file "just in case" you have
to debug the program. <G>
 
L

Li Chen

He needs to seek back to the beginning of the line before he writes:

file.each_line do |line|
if pat.match(line)
line.gsub!(pat,sub) #replace the line in place
file.seek(-line.length, IO::SEEK_CUR)
file.print line #write/update the file
end
end
end

But this will only work in the case where the replacement is the same
length at the original, if you you're either going to leave stuff
behind, or will overwrite the next line. In either case you're more
likely to end up with gibberish than something you like.

What am I supposed to do if the replacement is not same size?

Thanks,

Li
 
R

Rick DeNatale

What am I supposed to do if the replacement is not same size?

Write to another file, then rename when you are done.

This is standard posix practice.
 
R

Robert Klemme

Write to another file, then rename when you are done.

This is standard posix practice.

And you can even do it in a one liner. See ruby's command line options
-i and -p. You can then do

ruby -i.bak -pe 'gsub /.../, "..."' file

Kind regards

robert
 
L

Li Chen

Rick said:
He needs to seek back to the beginning of the line before he writes:

file.each_line do |line|
if pat.match(line)
line.gsub!(pat,sub) #replace the line in place
file.seek(-line.length, IO::SEEK_CUR)
file.print line #write/update the file
end
end
end

But this will only work in the case where the replacement is the same
length at the original, if you you're either going to leave stuff
behind, or will overwrite the next line. In either case you're more
likely to end up with gibberish than something you like.

HI Rick,

Now I work on a small project with deals with process files and upgrade
the them in place. Just as you point out the #seek only works if the
replacement is the same as the original. And the replacement will get
unpredictalbe results or fail if the length is different. I wonder if
other methods are available for this situation in Ruby?

Thanks,

Li
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,225
Members
46,815
Latest member
treekmostly22

Latest Threads

Top