2010-04-15 15 views
6

Entonces, ¿por qué no funciona? Estoy creando una expresión regular que coincidirá con una fórmula (que luego es parte de una descripción estándar más grande). Pero estoy atrapado aquí, ya que no parece querer combinar fórmulas integradas dentro de una fórmula.rubí recursivo regex

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 

Respuesta

7

Cuando se utiliza la sintaxis #{ }, Ruby convierte el objeto Regexp a cadena mediante to_s. Mira lo que sucede cuando se convierte un objeto Regexp en una cadena:

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)/ 

Para obtener la cadena que desea (en mi ejemplo, "bla"), utilice la Regexp#source método:

irb> re.source 
"blah" 

Así que para utilizar su ejemplo:

formula_sym = /((target's)?#{stat.source}|#{number_sym.source}|N#{number_sym.source})\%?/ 
+0

gracias ... y descubrí por qué no funcionaba ... supongo que debería haber formulado mi pregunta como "¿cómo puedo hacer que funcione? ... parece que # {formula.source} mostró que la fórmula todavía era nula. –

1

no se puede utilizar la repetición de esa manera: los #{formula} s en su definición de formula se convierten en cadenas vacías. Lo que desea está más allá de la capacidad de expresión regular: las expresiones regulares ni siquiera pueden coincidir con paréntesis anidados. Sospecho que necesitarás un analizador real para hacer lo que quieras. Consulte treetop, por ejemplo.

+0

excellent ... treetop me permitirá migrar mi especificación de definición actual fácilmente. ¡Gracias! –

3
/(
    (?<non_grouping_char> 
    [^\(\{\[\<\)\}\]\>] 
){0} 
    (?<parens_group> 
    \(\g<content> \) 
){0} 
    (?<brackets_group> 
    \[ \g<content> \] 
){0} 
    (?<chevrons_group> 
    \< \g<content> \> 
){0} 
    (?<braces_group> 
    \{ \g<content> \} 
){0} 
    (?<balanced_group> 
    (?> 
     \g<parens_group> | 
     \g<brackets_group> | 
     \g<chevrons_group> | 
     \g<braces_group> 
    ) 
){0} 
    (?<content> 
    (?> \g<balanced_group> | \g<non_grouping_char>)* 
){0} 
    \A \g<content> \Z 
)/uix 

Cerveza si esto te ayuda. Funciona para mi. Funciona en cualquier motor regexp que permita grupos nombrados. Validará cualquier contenido que no tenga grupos o grupos de caracteres anidados a cualquier profundidad.

+1

Si nos encontramos, seguro te pagaré una cerveza. ¿Cuál es tu sabor favorito? :) ¡Desde entonces, voto! – Stephan