I’m writing a ruby program that reads a file, reads sections out of that
file, writes a header to each section and then writes the whole file
back to disk. The problem is that if the section contains “\” which
mine does in places, ruby replaces these with a single “” without my
asking it to.
Here is the basics of the program:
body = “”
File.open(input, ‘r’) do |file|
body = file.read
end
if body =~ /^section\sheader(.*)section\sfooter/mi
original_section = $1
new_section = bit_at_top + original_section
new_body = body.sub(original_section, new_section)
File.open(input,'w') do |file|
file.write new_body
end
end
If the original_section contains “\” then this gets replaced by “”,
can I stop this happening?
Jeremy
On Fri, 24 Nov 2006, Jeremy W. wrote:
[...]
original_section = $1
new_section = bit_at_top + original_section
new_body = body.sub(original_section, new_section)
new_body = body.sub(Regexp.new(Regexp.quote(original_section)),
new_section)
File.open(input,‘w’) do |file|
file.write new_body
end
end
# Hugh
Hugh S. wrote:
On Fri, 24 Nov 2006, Jeremy W. wrote:
[...]
original_section = $1
new_section = bit_at_top + original_section
new_body = body.sub(original_section, new_section)
new_body = body.sub(Regexp.new(Regexp.quote(original_section)),
new_section)
File.open(input,‘w’) do |file|
file.write new_body
end
end
# Hugh
Makes no difference. String#sub states that metacharacters in the
pattern will not be interpreted if the pattern is a String and not a
Regexp.
Check it out:
irb(main):061:0> x
=> “section
header\nkjhKAJSHDKjashdkjASH\\\\\\\\KJahfdkasjhdfkajshdfjh\nsection
footer”
irb(main):062:0> y
=> “\nkjhKAJSHDKjashdkjASH\\\\\\\\KJahfdkasjhdfkajshdfjh\n”
irb(main):063:0> z
=> “xyzzy
\nkjhKAJSHDKjashdkjASH\\\\\\\\KJahfdkasjhdfkajshdfjh\n”
irb(main):064:0> x.sub(y,z)
=> “section headerxyzzy
\nkjhKAJSHDKjashdkjASH\\\\KJahfdkasjhdfkajshdfjh\nsection footer”
irb(main):065:0> x.sub(Regexp.new(Regexp.quote(y)),z)
=> “section headerxyzzy
\nkjhKAJSHDKjashdkjASH\\\\KJahfdkasjhdfkajshdfjh\nsection footer”
Identical results.
The problem is that the backslashes in the REPLACEMENT string are being
interpreted.
The way to overcome this is to use the block form of sub:
new_body = body.sub(original_section) {|s| s = new_section}
Edwin F. wrote:
irb(main):062:0> y
Identical results.
The problem is that the backslashes in the REPLACEMENT string are being
interpreted.
The way to overcome this is to use the block form of sub:
new_body = body.sub(original_section) {|s| s = new_section}
Thanks, I might try that, it’s better looking than my solution, which
was:
m = Regexp.new("(" + Regexp.escape(original_section) + “)”).match(body)
body[(m.begin(1)…m.end(1)-1)] = new_section
Edwin F. wrote:
new_body = body.sub(original_section) {|s| s = new_section}
Using only {new_section} for the block should suffice, I doubt assigning
to a block parameter actually does anything outside the block.
David V.
On Fri, 24 Nov 2006, Edwin F. wrote:
Hugh S. wrote:
On Fri, 24 Nov 2006, Jeremy W. wrote:
new_body = body.sub(original_section, new_section)
new_body = body.sub(Regexp.new(Regexp.quote(original_section)),
new_section)
[…]
end
# Hugh
Makes no difference. String#sub states that metacharacters in the
pattern will not be interpreted if the pattern is a String and not a
Regexp.
[…]
The problem is that the backslashes in the REPLACEMENT string are being
interpreted.
Oops!
Hugh
or you can use references:
old_section = $1
new_body = body.sub(old_section, bit_at_top + ‘&’)
& = the last match.
if there was gsub instead of sub, this would be slower as the
replacement takes place on every occurence. In this case, however,
there’s max 1 occurence.
You can do as well:
- body = “”
- File.open(input, ‘r’) do |file|
- body = file.read
- end
and
File.open(input,'w') do |file|
file.write new_body
- end unless new_body == body
Jan S. wrote:
file.write new_body
- end unless new_body == body
thanks, thats useful to know for the future. this was something of a run
once and its done program, and i’ve um run it now, so its done.
David V. wrote:
Edwin F. wrote:
new_body = body.sub(original_section) {|s| s = new_section}
Using only {new_section} for the block should suffice, I doubt assigning
to a block parameter actually does anything outside the block.
David V.
Yes, I see. It works with the assignment as it is simply because the
result of the assignment expression becomes the return value of the
block. Thanks for pointing that out. I’m still learning Ruby :). And
loving it.
Hi,
At Fri, 24 Nov 2006 01:39:05 +0900,
Jeremy W. wrote in [ruby-talk:226339]:
if body =~ /^section\sheader(.*)section\sfooter/mi
original_section = $1
new_section = bit_at_top + original_section
new_body = body.sub(original_section, new_section)
You can use bang-version to replace and tell if it is done, at once.
if body.sub!(/^(section\sheader)(.*section\sfooter)/mi)
{$1+bit_at_top+$2}
File.open(input,'w') do |file|
file.write body
Some more remarks:
On 23.11.2006 17:53, Hugh S. wrote:
On Fri, 24 Nov 2006, Jeremy W. wrote:
[...]
The problem is that if the section contains “\” which mine does in places,
ruby replaces these with a single “” without my asking it to.
Here is the basics of the program:
body = “”
Initializing body with an empty string is superfluous - nil is more
efficient, but:
File.open(input, ‘r’) do |file|
body = file.read
end
You could as well replace those lines with
body = File.read input
if body =~ /^section\sheader(.*)section\sfooter/mi
Dangerous to use .* which is greedy and will break if there are more
sections in one file!
original_section = $1
new_section = bit_at_top + original_section
new_body = body.sub(original_section, new_section)
new_body = body.sub(Regexp.new(Regexp.quote(original_section)),
new_section)
Now you do a replacement with sub which might replace some completely
different piece of text (i.e. especially if the text of original_section
appears outside a section or otherwise in multiple places.
File.open(input,‘w’) do |file|
file.write new_body
end
end
# Hugh
So, combining these you get:
body = File.read input
if body.gsub!( %r{^(section\sheader)(.*?)(?=section\sfooter)}mi,
‘\1your_head\2’)
File.open(input, “w”) {|io| io.write body}
end
Kind regards
robert
On 23.11.2006 19:50, Jeremy W. wrote:
footer"
m = Regexp.new("(" + Regexp.escape(original_section) + “)”).match(body)
body[(m.begin(1)…m.end(1)-1)] = new_section
Frankly, I don’t understand why everybody is trying to fix backslashes
in replacement strings when there is gsub and grouping. It’s easier and
more robust if you use grouping and use those groups in the replacement.
No problems with slashes in there (see my other posting).
Cheers
robert