2012-10-11 89 views
14

Ésta es de Ruby 1.8.7, pero debe ser el mismo que para 1.9.xRubí Separar una cadena con expresiones regulares

Estoy tratando de dividir una cadena, por ejemplo:

a = "foo.bar.size.split('.').last" 
# trying to split into ["foo", "bar","split('.')","last"] 

Básicamente partiéndolo en ordena que representa, estoy tratando de hacerlo con regexp pero no sabe cómo, idea era utilizar expresiones regulares

a.split(/[a-z\(\)](\.)[a-z\(\)]/) 

Aquí tratando de usar grupo (\.) para dividirlo, pero este parece no ser un buen enfoque.

+1

No es tan fácil como crees. – sawa

+1

@sawa: ¿ha cerrado una pregunta porque piensa que es demasiado difícil? – iconoclast

+0

@iconoclast No lo recuerdo, pero no por la razón que piensas. – sawa

Respuesta

23

creo que esto lo haría:

a.split(/\.(?=[\w])/) 

no sé cuánto sabe acerca de expresiones regulares, pero el (?=[\w]) es una búsqueda hacia delante que dice "sólo se corresponde con el punto si el carácter siguiente es una carta tipo de personaje ". Un lookahead en realidad no captará el texto que coincide. Simplemente "mira". El resultado es exactamente lo que está buscando:

> a.split(/\.(?=[\w])/) 
=> ["foo", "bar", "size", "split('.')", "last"] 
+0

Guau, excelente y gracias por la información sobre el futuro. No, yo no sabía eso y es excelente para aprender parece muy útil. –

+1

De nada. Este sitio es impresionante: http://www.regular-expressions.info/ –

+1

Esto dividirá una cadena como '" foo.bar.size.split ('. Bar'). Last "' into '[" foo ", "barra", "tamaño", "división ('", "barra") "," última "]'. – sawa

2

aquí No tengo ruby ​​env. Intenté con python re.split().

In : re.split("(?<!')\.(?!')",a) 
Out: ['foo', 'bar', 'size', "split('.')", 'last'] 

la expresión regular anterior tiene búsqueda negativa hacia delante Y de búsqueda hacia atrás, para asegurarse de que sólo el "punto" entre comillas simples no funcionará como separador.

por supuesto, para el ejemplo dado por usted, uno de lookbehind o lookahead es suficiente. puede elegir el camino correcto para su requerimiento.

+0

Como habrá notado, esto no funcionará correctamente para '[" foo "," bar "," size "," split ('o.b') "," last "]'. – sawa

7

Me temo que las expresiones regulares no te llevarán muy lejos. Considere, por ejemplo, las siguientes expresiones (que también son válidos Rubí)

"(foo.bar.size.split('.')).last" 
"(foo.bar.size.split '.').last" 
"(foo.bar.size.split '(.) . .(). .').last" 

El problema es que la lista de llamadas es en realidad un árbol de llamadas. La solución más fácil a la vista es probablemente usar un analizador Ruby y transformar el árbol de análisis sintáctico de acuerdo a sus necesidades (en este ejemplo estamos en descendente en el árbol de llamadas, reuniendo las llamadas en una lista):

# gem install ruby_parser 
# gem install awesome_print 
require 'ruby_parser' 
require 'ap' 

def calls_as_list code 
    tree = RubyParser.new.parse(code) 

    t = tree 
    calls = [] 

    while t 
     # gather arguments if present 
     args = nil 
     if t[3][0] == :arglist 
      args = t[3][1..-1].to_a 
     end 
     # append all information to our list 
     calls << [t[2].to_s, args] 
     # descend to next call 
     t = t[1] 
    end 

    calls.reverse 
end 

p calls_as_list "foo.bar.size.split('.').last" 
#=> [["foo", []], ["bar", []], ["size", []], ["split", [[:str, "."]]], ["last", []]] 
p calls_as_list "puts 3, 4" 
#=> [["puts", [[:lit, 3], [:lit, 4]]]] 

Y para mostrar el árbol de análisis sintáctico de cualquier entrada:

ap RubyParser.new.parse("puts 3, 4") 
Cuestiones relacionadas