0

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
3
  • Is your input file a php file? Commented Nov 8, 2012 at 0:33
  • I assume you need to keep the comments and other info, so running php on the file to do the replacements would not be an option. Commented Nov 8, 2012 at 0:40
  • The problem with regex, is that their siren call will woo you into believing you should try to do everything inside them. Break it down into smaller chunks to preserve your sanity, and don't be afraid to combine the results of the individual chunks with other code. Nobody ever said we had to do everything with regex. Fer instance, see my answer. Commented Nov 8, 2012 at 1:12

2 Answers 2

1

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"
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks the problem for keyvalr(content, "bla", "newbla") replaces the entire line "$myuser['bla'] = 'bla';" to "newbla"
oh right. I don't know the correct ruby-syntax for this, but you can create capturing groups like this: /(\$bla\[\'#{key}\'\]\s+\=\s+\'=)[^']*(\')/ and then replace this with "\1newbla\2". \1 and \2 will contain what was matched in the two sets of parentheses.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.