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


#1

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.


#2

Lloyd Z. <ljz asfast.com> writes:

[ … ]

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.


#3

Lloyd Z. removed_email_address@domain.invalid wrote:

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…! :slight_smile: m.


#4

On Tue, 17 Mar 2009 13:59:24 -0500, Lloyd Z. wrote:

This works as long as $repl doesn’t contain any references to matched
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


#5

On Tue, 17 Mar 2009 14:52:08 -0500, Lloyd Z. wrote:

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.