user391986
user391986

Reputation: 30886

ruby find and replace portion of string

I have a large file in a ruby variable, it follows a common pattern like so:

// ...

// comment
$myuser['bla'] = 'bla';

// comment
$myuser['bla2'] = 'bla2';

// ...

I am trying to given a 'key' replace the 'value'

This replaces the entire string how do I fix it? Another method I thought is to do it in two steps, step one would be to find the value within the quotes then to perform a string replace, what's best?

def keyvalr(content, key, value)
    return content.gsub(/\$bla\[\'#{key}\'\]\s+\=\s+\'(.*)\'/) {|m| value }
end

Upvotes: 0

Views: 359

Answers (2)

the Tin Man
the Tin Man

Reputation: 160551

I'd use something like:

text = %q{
// ...

// comment
$myuser['bla'] = 'bla';

// comment
$myuser['bla2'] = 'bla2';

// ...
}

from_to = {
  'bla'  => 'foo',
  'bla2' => 'bar'
}

puts text.gsub(/\['([^']+)'\] = '([^']+)'/) { |t|
  key, val = t.scan(/'([^']+)'/).flatten
  "['%s'] = '%s'" % [ key, from_to[key] ]
}

Which outputs:

// ...

// comment
$myuser['bla'] = 'foo';

// comment
$myuser['bla2'] = 'bar';

// ...

This is how it works:

If I do:

puts text.gsub(/\['([^']+)'\] = '([^']+)'/) { |t|
  puts t
}

I see:

['bla'] = 'bla'
['bla2'] = 'bla2'

Then I tried:

"['bla'] = 'bla'".scan(/'([^']+)'/).flatten
=> ["bla", "bla"]

That gave me a key, "value" pair, so I could use a hash to look-up the replacement value.

Sticking it inside a gsub block meant whatever matched got replaced by my return value for the block, so I created a string to replace the "hit" and let gsub do its "thang".

I'm not a big believer in using long regex. I've had to maintain too much code that tried to use complex patterns, and got something wrong, and failed to accomplish what was intended 100% of the time. They're very powerful, but maintenance of code is a lot harder/worse than developing it, so I try to keep patterns I write in spoon-size pieces, having mercy on those who follow me in maintaining the code.

Upvotes: 0

Martin Ender
Martin Ender

Reputation: 44259

The .* is greedy and consumes as much as possible (everything until the very last '). Make that . a [^'] then it is impossible for it to go past the first closing '.

/(\$bla\[\'#{key}\'\]\s+\=\s+\')[^']*(\')/

I also added parentheses to capture everything except for the value, which is to be replaced. The first set of parens will correspond to \1 and the second to \2. So that you replace the match of this with:

"\1yournewvaluehere\2"

Upvotes: 1

Related Questions