Interpolating $1, etc., from within a gsub block

L

Lloyd Zusman

I'm trying to use the block form of gsub in order to do substitution
involving an interpolation stored within a variable, but I can't
figure out how to get it to work. Here's a simplified case of what
I'm trying to do:

$fromre = Regexp.compile(ARGV[0])
$repl = ARGV[1]
$replcount = 0

string = "... something arbitrary ..."

string.gsub!($fromre) {
|x|
$replcount += 1
$repl
}

As you can see, the regexp comes in on the command line, as well as
the replacement. I want to do this substution using the block form so
I can count the number of replacements that were made.

This works as long as $repl doesn't contain any references to matched
patterns. However, if this program is called 'myprog' and I do the
following, the replacement of $1 with the indicated subexpression
doesn't occur:

myprog 'abc(\S+)def' 'NEW-$1-MATCH'

In other words, if the string being substituted is this, "abcFOOBARdef",
the result is not "NEW-FOOBAR-MATCH" as I would like it to be, but rather,
"NEW-$1-MATCH".

It's clear why this doesn't work, but I can't figure out what construct
to use within the gsub block or on the command line to make sure that it
_does_ work.

I also tried this, and not surprisingly, it didn't work, either:

myprog 'abc(\S+)def' 'NEW-#{$1}-MATCH'

Can anyone suggest how I can accomplish this?

Thanks in advance.
 
L

Lloyd Zusman

Lloyd Zusman said:
[ ... ]

string.gsub!($fromre) {
|x|
$replcount += 1
$repl
}

Well, I came up with the following, but I'm still wondering if there
is a more elegant way to do this:

string.gsub!($fromre) {
|x|
$replcount += 1
eval "$result = \"#{$to}\""
$result
}

Then, I have to invoke my program as follows:

myprog 'abc(\S+)def' 'NEW-#{$1}-MATCH'

Is this the best I can do, or is there something more elegant?

Thanks.
 
M

matt neuburg

Lloyd Zusman said:
I'm trying to use the block form of gsub in order to do substitution
involving an interpolation stored within a variable, but I can't
figure out how to get it to work. Here's a simplified case of what
I'm trying to do:

$fromre = Regexp.compile(ARGV[0])
$repl = ARGV[1]
$replcount = 0

string = "... something arbitrary ..."

string.gsub!($fromre) {
|x|
$replcount += 1
$repl
}

As you can see, the regexp comes in on the command line, as well as
the replacement. I want to do this substution using the block form so
I can count the number of replacements that were made.

This works as long as $repl doesn't contain any references to matched
patterns. However, if this program is called 'myprog' and I do the
following, the replacement of $1 with the indicated subexpression
doesn't occur:

myprog 'abc(\S+)def' 'NEW-$1-MATCH'

In other words, if the string being substituted is this, "abcFOOBARdef",
the result is not "NEW-FOOBAR-MATCH" as I would like it to be, but rather,
"NEW-$1-MATCH".

$fromre = /abc(\S+)def/
$repl = '"NEW-#{$1}-MATCH"'
string = "abcFOOBARdef"

string.gsub!($fromre) { |x|
instance_eval($repl)
}

I don't like it any better than you do...! :) m.
 
K

Ken Bloom

I'm trying to use the block form of gsub in order to do substitution
involving an interpolation stored within a variable, but I can't figure
out how to get it to work. Here's a simplified case of what I'm trying
to do:

$fromre = Regexp.compile(ARGV[0])
$repl = ARGV[1]
$replcount = 0

string = "... something arbitrary ..."

string.gsub!($fromre) {
|x|
$replcount += 1
$repl
}

As you can see, the regexp comes in on the command line, as well as the
replacement. I want to do this substution using the block form so I can
count the number of replacements that were made.

This works as long as $repl doesn't contain any references to matched
patterns. However, if this program is called 'myprog' and I do the
following, the replacement of $1 with the indicated subexpression
doesn't occur:

myprog 'abc(\S+)def' 'NEW-$1-MATCH'

In other words, if the string being substituted is this, "abcFOOBARdef",
the result is not "NEW-FOOBAR-MATCH" as I would like it to be, but
rather, "NEW-$1-MATCH".

It's clear why this doesn't work, but I can't figure out what construct
to use within the gsub block or on the command line to make sure that it
_does_ work.

I also tried this, and not surprisingly, it didn't work, either:

myprog 'abc(\S+)def' 'NEW-#{$1}-MATCH'

Can anyone suggest how I can accomplish this?

Thanks in advance.

Variable interpolation only works for string literals inside ruby code.
If you bring in the string from anywhere else, you'll can use eval

eval '"'+string+'"' and hope there are no injection attacks in the string.

Alternatively, you can roll your own substitution:

string.gsub!($fromre) do |match|
matchdata=Regexp.last_match
$repl.gsub(/\$\d+/) do |subst|
matchdata[subst[1..-1].to_i]
end
end

--Ken
 
K

Ken Bloom

Lloyd Zusman said:
[ ... ]

string.gsub!($fromre) {
|x|
$replcount += 1
$repl
}
Well, I came up with the following, but I'm still wondering if there is
a more elegant way to do this:

string.gsub!($fromre) {
|x|
$replcount += 1
eval "$result = \"#{$to}\""
$result
}

I think you're going overboard with variables (and global variables in
particular)

an eval "\"#{$to}\"" would have been sufficient here, and if you really
needed a new variable, then calling it simply result (without the dollar
sign) would have given you a local variable.
 

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

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,162
Latest member
GertrudeMa
Top