2011-05-25 12 views
12

He notado un efecto secundario en Ruby/Oniguruma que solo está presente en 1 de 4 afirmaciones aparentemente equivalentes. ¿Por qué la variable day se define en 009, pero no en 003, 005 o 007?¿Por qué el operador = ~ solo a veces tiene efectos secundarios?

irb(main):001:0> r = /(?<day>\d\d):(?<mon>\d\d)/ 
=> /(?<day>\d\d):(?<mon>\d\d)/ 

irb(main):002:0> r =~ "24:12" 
=> 0 
irb(main):003:0> day 
NameError: undefined local variable or method `day' 

irb(main):004:0> "24:12" =~ r 
=> 0 
irb(main):005:0> day 
NameError: undefined local variable or method `day' 


irb(main):006:0> "24:12" =~ /(?<day>\d\d):(?<mon>\d\d)/ 
=> 0 
irb(main):007:0> day 
NameError: undefined local variable or method `day' 


irb(main):008:0> /(?<day>\d\d):(?<mon>\d\d)/ =~ "24:12" 
=> 0 
irb(main):009:0> day 
=> "24" 

nb # 1: Es la misma expresión regular y la misma cadena en los cuatro casos.

nb # 2: He verificado el comportamiento en MS Windows y Ubuntu Linux.

+2

Nota: aunque este no es el caso aquí, debe tener cuidado cuando juegue con variables locales en IRb. Pueden comportarse de forma ligeramente diferente en IRb que en un script, debido a la forma en que el código se evalúa en IRb. Siempre escriba scripts para confirmar. –

+0

Buen punto, Jörg. –

Respuesta

13

Cuando llame al "24:12" =~ r, realmente llama al "24:12".=~(r). Por lo tanto, String#=~ simplemente devuelve la posición en que se inicia la coincidencia, o nula si no hay coincidencia.

Pero cuando se llama /(?<day>\d\d):(?<mon>\d\d)/ =~ "24:12" en realidad se llama Regexp#=~

Y como la documentación dice

Si = ~ se utiliza con una expresión regular literal con capturas con nombre, cadenas capturadas (o nula) es asignado a las variables locales nombradas por los nombres de captura.

¿qué pasa con 003:

La asignación no se produce si el expresión regular no es un literal.

re = /(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/ 
    re =~ " x = y " 
    p lhs # undefined local variable 
    p rhs # undefined local variable 

y

La asignación no se produce si la expresión regular se coloca en el lado derecho.
"x = y" = ~ /(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/
p izda, dcha # indefinido variable local

+0

Gracias Nash. Una muy buena respuesta. Pero también puede explicar '003' en la pregunta, es decir, una expresión regular compilada (no una expresión regular) recibe el mensaje' = ~ 'y no asigna la variable local. –

+0

¡De nada! Ver actualización –

+1

"Cadenas capturadas asignadas ...", "La asignación no se produce ..."? Extraña gramática ... –

1

creo que 003 no es compatible porque es un objeto Regexp completo soplado en Rubyland en ese momento, posiblemente con métodos anulados y tal. Eso hace que el alcance de los lugareños asignados sea mucho más complicado.

+0

Gracias, James.Tenía otra idea sobre la intención de los creadores de Ruby, pero probablemente tengas razón de que es un problema técnico. –

Cuestiones relacionadas