First, don’t top-post (like this). It’s annoying.
On Saturday 27 February 2010 01:25:02 pm Dudebot wrote:
I need it to interpolate the value of the expressions, not the
expressions themselves. Is this not possible in Ruby?
It’s certainly possible, but not with gsub. Think about what you’re
asking.:
newtext = text.gsub( some_regex, some_string )
By the time gsub sees those arguments, both some_regex and some_string
will
have been evaluated. That is, the standard Ruby string interpolation
will have
already resolved. As an example:
count = 0
newtext = text.gsub( /(.*?)</field>/, “#{count+=1}” )
You’ll just get 1, not 1,2 as you might expect. Think about why that
happens.
It happens that way because by the time gsub gets called, “#{count+=1}”
has
already been replaced by the results of evaluating that expression, and
is now
just a string.
What you want is to replace it with the results of evaluating a block,
which
is an entirely different animal. It’s possible gsub can do that, but
before I
provide any kind of solution there, are you sure this is how you want to
do
this? Because it looks like you’re trying to use regexes to parse XML.
DO NOT USE REGEX TO PARSE XML.
It is the wrong tool for the job. There are a billion special-cases in
XML,
let alone HTML. It may be possible to write a correct regex, but you
won’t be
able to – nor would I want to try. There are already dozens of
libraries to
do this for you, it’s a thoroughly-solved problem, and there’s no good
reason
to try to do it again yourself… I’d suggest Nokogiri.
Once you’ve actually parsed it, the solution is much easier:
It’s not valid XML without a root element.
It doesn’t have to be called body, but it has to exist.
text = “#{text}”
doc = Nokogiri.parse(text)
(doc / ‘field’).each{|e| e.content = eval e.text}
Of course, the use of ‘eval’ should scare you. Your original
implementation,
and this one, is ridiculously insecure. Don’t use local variables for
this!
(That comes up about as often on this list as people trying to use
regexes to
parse XML, and it makes about as much sense.) Instead, use a hash:
h = {‘wibble’ => 2.0, ‘bobble’ => 3.0}
(doc / ‘field’).each{|e| e.content = h[e.text]}
And to turn it back into XML:
doc.to_s