simple one-liners: last line missing

T

Tobi Reif

Hi

Let's say I'd want to modify each line of a file. Here's the dummy
data:

$ cat data.txt
first foo
second foo
third foo
$

This works:

$ ruby -ne '$_ =~ /(\S+)\s+(\S+)/;puts "#{$2} #{$1}"' data.txt
foo first
foo second
foo third
$

I don't really need to achieve that modification. Instead I'd like to
understand why the following version one doesn't work:

$ ruby -pe 'sub(/(\S+)\s+(\S+)/,"#{$2} #{$1}")' data.txt

foo first
foo second
$

TIA,
Tobi
 
T

ts

T> $ ruby -pe 'sub(/(\S+)\s+(\S+)/,"#{$2} #{$1}")' data.txt

The replacement string is build when #sub is called

for the first call $1 = $2 = nil ==> the replacement string is ' '

for the second call, $1 = 'first', $2 = 'foo' ==> the replacement string
is 'foo first'

etc,


Guy Decoux
 
A

Andrew Johnson

[snip]
I don't really need to achieve that modification. Instead I'd like to
understand why the following version one doesn't work:

$ ruby -pe 'sub(/(\S+)\s+(\S+)/,"#{$2} #{$1}")' data.txt

foo first
foo second
$


When doing substitutions with a string replacement, you do not get what
you might expect because the interpolation of #{$1} in the replacement
string happens when the arguments are evaluated and passed into the sub()
or gsub() methods, not during the match. That means they will have whatever
value they had from the last successful match (or nil, as in your case with
the first line printed).

To access backreferences within a replacement string, you may use the same
notation as you do for backreferences within the pattern itself: \1, \2,
etc. For your example:

ruby -pe 'sub(/(\S+)\s+(\S+)/,%q(\2 \1))' data.txt

Alternatively, you may use the block form of replacement, in which case the
block is evaluated at match-time and $1, $2, etc are available and refer to
their respective backreferences within the current match:

ruby -pe 'sub(/(\S+)\s+(\S+)/){"#{$2} #{$1}"}' data.txt

cheer's
andrew
 
T

Tobi Reif

T> $ ruby -pe 'sub(/(\S+)\s+(\S+)/,"#{$2} #{$1}")' data.txt

The replacement string is build when #sub is called

for the first call $1 = $2 = nil ==> the replacement string is ' '

for the second call, $1 = 'first', $2 = 'foo' ==> the replacement string
is 'foo first'

etc,

Thanks. I guess my (current) opinion is that it should work.

Tobi
 

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,767
Messages
2,569,573
Members
45,046
Latest member
Gavizuho

Latest Threads

Top