2010-01-06 17 views
7

Necesito dividir una cadena en una lista de partes en Ruby, pero necesito ignorar cosas dentro de paramentheses. Por ejemplo:¿Separar una cadena en Ruby, ignorando el contenido de paréntesis?

A +4, B +6, C (hello, goodbye) +5, D +3 

me gustaría la lista el resultado es:

[0]A +4 
[1]B +6 
[2]C (hello, goodbye) +5 
[3]D +3 

Pero no puede simplemente dividir en comas, porque eso sería dividir el contenido de los paréntesis. ¿Hay alguna manera de dividir las cosas sin preprocesar las comas entre llaves en otra cosa?

Gracias.

+0

Cuidado con las caras frowny :-(ensuciar el análisis sintáctico –

Respuesta

13

Prueba esto:

s = 'A +4, B +6, C (hello, goodbye) +5, D +3' 
tokens = s.scan(/(?:\(.*?\)|[^,])+/) 
tokens.each {|t| puts t.strip} 

Salida:

A +4 
B +6 
C (hello, goodbye) +5 
D +3 

Una breve explicación:

(?:  # open non-capturing group 1 
    \(  # match '(' 
    .*?  # reluctatly match zero or more character other than line breaks 
    \)  # match ')' 
    |  # OR 
    [^,]  # match something other than a comma 
)+   # close non-capturing group 1 and repeat it one or more times 

Otra opción es dividir en una coma seguida de algunos espacios sólo cuando la primera paréntesis que se puede ver al mirar hacia adelante es un paréntesis de apertura (o no hay paréntesis en absoluto: es decir. Al final de la cadena):

s = 'A +4, B +6, C (hello, goodbye) +5, D +3' 
tokens = s.split(/,\s*(?=[^()]*(?:\(|$))/) 
tokens.each {|t| puts t} 

producirá el mismo resultado, pero me parece que el limpiador scan método.

+0

# => [ "A 4", "B 6", "C (! hola, adiós) +5 "," D +3 "] Parece perfecto para mí. Podría querer #trim it para eliminar los espacios en blanco circundantes. –

+0

:) Ya vi los espacios y agregué' trim' –

+0

Gran respuesta, gracias:) – Colen

5
string = "A +4, B +6, C (hello, goodbye) +5, D +3" 
string.split(/ *, *(?=[^\)]*?(?:\(|$))/) 
# => ["A +4", "B +6", "C (hello, goodbye) +5", "D +3"] 

¿Cómo funciona esta expresión regular:

/ 
    *, *  # find comma, ignoring leading and trailing spaces. 
    (?=   # (Pattern in here is matched against but is not returned as part of the match.) 
    [^\)]*? # optionally, find a sequence of zero or more characters that are not ')' 
    (?:  # <non-capturing parentheses group> 
     \(  #  left paren ')' 
     |  #  - OR - 
     $  #  (end of string) 
    ) 
) 
/
+0

¡Eso puede ser un poco críptico sin una explicación para el entusiasta de la leyenda regex débil que probablemente sea el OP! :). Pero una buena solución, sin embargo. –

+0

¿Cómo funciona esto? No pude encontrar ninguna buena documentación sobre cómo funcionaba Regex con split - como Bart K. dice que no soy tan bueno con las expresiones regulares – Colen

+0

@Colen, publiqué una expresión regular muy similar como una segunda solución que incluye una explicación. –

Cuestiones relacionadas