views:

192

answers:

3

So why is this not working? I'm creating a regex that will match a formula (which is then part of a larger standard description). But I'm stuck here, as it doesn't appear to want to match embedded formulas within a formula.

stat        = /(Stat3|Stat2|Stat1)/

number_sym  = /[0-9]*/
formula_sym = /((target's )?#{stat}|#{number_sym}|N#{number_sym})\%?/
math_sym    = /(\+|\-|\*|\/|\%)/

formula     = /^\((#{formula}|#{formula_sym})( #{math_sym} (#{formula}|#{formula_sym}))?\)$/

p "(target's Stat2 * N1%)".match(formula).to_s #matches
p "((target's Stat2 * N1%) + 3)".match(formula).to_s #no match
p "(Stat1 + ((target's Stat2 * N1%) + 3))".match(formula).to_s #no match
+1  A: 

When you use the #{ } syntax, Ruby converts the Regexp object to a string using to_s. Look what happens when you convert a Regexp object to a string:

irb> re = /blah/
  => /blah/
irb> re.to_s
  => "(?-mix:blah)"
irb> "my regex: #{re}"
  => "my regex: (?-mix:blah)"
irb> /my regex: #{re}/
  => /my regex: (?-mix:blah)/

To get the string you want (in my example, "blah"), use the Regexp#source method:

irb> re.source
"blah"

So to use your example:

formula_sym = /((target's )?#{stat.source}|#{number_sym.source}|N#{number_sym.source})\%?/
yjerem
thanks ... and I did discover why it wasn't working ... guess I should have phrased my question as "how can I get it working" .... looks like #{formula.source} showed that formula was still nil.
Reed Debaets
+1  A: 

Bear in mind: using a regex against a math formula is not recommended. Validating a formula is usually not at all possible.

Depending on your application: you should use or write a parser...

That said, there is a post on matching parens HERE

drewk
yes ... i was just thinking it may be easier to use regex considering how I have my standard description currently defined.
Reed Debaets
This doesn't work with ruby. Ruby regexen don't have recursion.
sepp2k
+1  A: 

You can't use recursion like that: the #{formula}s in your definition of formula are converted into empty strings. What you want is beyond regular expression's ability -- regular expressions cannot even match nested parentheses. I suspect you will need an actual parser to do what you want. Check out treetop, for example.

Kathy Van Stone
excellent ... treetop will allow me to migrate my current definition spec into it easily. Thanks!
Reed Debaets