2011-06-01 17 views
11

Tomemos, por ejemplo, tengo una cadena como esta:dividir una cadena con múltiples delimitadores en Ruby

options = "Cake or pie, ice cream, or pudding" 

Quiero ser capaz de dividir la cadena a través de or, , y , or.

La cosa es, es que he sido capaz de hacerlo, pero sólo mediante el análisis , y , or primero, y luego dividir cada elemento de la matriz en or, aplanando la matriz resultante después como tales:

options = options.split(/(?:\s?or\s)*([^,]+)(?:,\s*)*/).reject(&:empty?); 
options.each_index {|index| options[index] = options[index].sub("?","").split(" or "); } 

La matriz resultante es la siguiente: ["Cake", "pie", "ice cream", "pudding"]

¿Hay alguna manera más eficiente (o más fácil) de dividir mi cadena en esos tres delimitadores?

Respuesta

14

¿Qué hay de lo siguiente:

options.gsub(/ or /i, ",").split(",").map(&:strip).reject(&:empty?) 
  • reemplaza todos los delimitadores pero el ,
  • lo divide en ,
  • recorta cada personaje, ya que cosas como ice cream con un espacio inicial podría dejarse
  • elimina todas las cadenas en blanco
+2

Parece mucho más fácil de leer, aunque hay dos cosas: una,' &: empty' debe cambiarse a '&: empty?', y dos,' "o" 'podrían cambiarse a'/o/i' para acomodar mayúsculas 'OR' también. – Mark

+0

Gracias por eso - '&: empty' ni siquiera funciona y de hecho lo he probado con' &: empty? '; y la expresión regular es una adición útil también. – mabako

9

En primer lugar, el método podría simplificarse un poco con Array#flatten:

>> options.split(',').map{|x|x.split 'or'}.flatten.map(&:strip).reject(&:empty?) 
=> ["Cake", "pie", "ice cream", "pudding"] 

yo preferiría usar una sola expresión regular:

>> options.split /\s*, or\s+|\s*,\s*|\s+or\s+/ 
=> ["Cake", "pie", "ice cream", "pudding"] 

Usted puede utilizar | en una expresión regular para dar alternativas y poner , or primero garantiza que no producirá un elemento vacío. La captura del espacio en blanco con la expresión regular es probablemente la mejor para la eficiencia, ya que no es necesario escanear la matriz de nuevo.

Como Zabba señala, todavía se puede querer a rechazar artículos vacíos, lo que provocó esta solución:

>> options.split(/,|\sor\s/).map(&:strip).reject(&:empty?) 
=> ["Cake", "pie", "ice cream", "pudding"] 
+1

¿Qué sucede si la cadena comienza con un ', o' por alguna razón? Su expresión regular producirá cadenas en blanco/vacías. – Zabba

+2

Bueno, queremos tratarlo como un delimitador. Un delimitador al comienzo indica un artículo vacío. Pero lo abordaré. –

+0

Hay un problema con la segunda solución, es que una palabra que es algo así como "smore's" produce '[" sm "," e's "]'. probablemente sería mejor tener la expresión regular como '/, | \ sor \ s /'. (Y opcionalmente, use el modo 'i' para aceptar 'O' en mayúsculas también.) – Mark

3

Como "or" y "," hace lo mismo, lo mejor es decirle a la expresión regular que múltiples casos deben ser tratado igual que una sola caja:

options = "Cake or pie, ice cream, or pudding" 
regex = /(?:\s*(?:,|or)\s*)+/ 
options.split(regex) 
Cuestiones relacionadas