2010-10-18 11 views
5

Soy un poco nuevo en expresiones regulares con Ruby, (o supongo que en general regex), pero me preguntaba si había una forma pragmática de hacer coincidir una cadena con una matriz.Ruby regex matching strings from a array?

Me explico, decir que tengo una lista de ingredientes en este caso:

1 1/3 cups all-purpose flour 
2 teaspoons ground cinnamon 
8 ounces shredded mozzarella cheese 

En última instancia necesidad de dividir los ingredientes en su respectivo "cantidad y la medición" y "nombre del ingrediente", así como en el caso de 2 teaspoons ground cinnamon, se dividirá en "8 ounces y shredded mozzarella cheese

así que en vez de tener un enorme tiempo de expresiones regulares como:. (cup\w*|teaspoon\w*ounce\w* .......), ¿cómo puedo utilizar una matriz para mantener esos valores fuera de la expresión regular

?

actualización

me hicieron esto (gracias cwninja):

# I think the all units should be just singular, then 
    # use ruby function to pluralize them. 

units = [ 
    'tablespoon', 
    'teaspoon', 
    'cup', 
    'can', 
    'quart', 
    'gallon', 
    'pinch', 
    'pound', 
    'pint', 
    'fluid ounce', 
    'ounce' 
    # ... shortened for brevity 
] 

joined_units = (units.collect{|u| u.pluralize} + units).join('|') 

# There are actually many ingredients, so this is actually an iterator 
# but for example sake we are going to just show one. 
ingredient = "1 (10 ounce) can diced tomatoes and green chilies, undrained" 

ingredient.split(/([\d\/\.\s]+(\([^)]+\))?)\s(#{joined_units})?\s?(.*)/i) 

Esto me da cerca de lo que quiero, así que creo que esta es la dirección que quiero ir.

puts "measurement: #{arr[1]}" 
puts "unit: #{arr[-2] if arr.size > 3}" 
puts "title: #{arr[-1].strip}" 

Respuesta

22

Personaly que acababa de construir la expresión regular mediante programación, puede hacerlo :

mediciones = [...] MEASUREMENTS_RE = Regexp.new (measurements.join ("|"))

... luego use la expresión regular.

Mientras lo guarde y no siga recreando, debería ser bastante eficiente.

+7

también uso este enfoque, con un pequeño ajuste: Regexp.union (mediciones) en lugar de Regexp.new (measurements.join ("|")), mismo resultado, mucho más limpio – Coelhone

3

Para una matriz un, algo como esto debería funcionar:

a.each do |line| 
    parts = /^([\d\s\.\/]+)\s+(\w+)\s+(.*)$/.match(line) 
    # Do something with parts[1 .. 3] 
end 

Por ejemplo:

a = [ 
    '1 1/3 cups all-purpose flour', 
    '2 teaspoons ground cinnamon', 
    '8 ounces shredded mozzarella cheese', 
    '1.5 liters brandy', 
] 
puts "amount\tunits\tingredient" 
a.each do |line| 
    parts = /^([\d\s\.\/]+)\s+(\w+)\s+(.*)$/.match(line) 
    puts parts[1 .. 3].join("\t") 
end 
+0

+ 1 Gracias por su respuesta, por extraño que parezca, su respuesta es como por el modo en que describí mi problema, no creo que fuera muy claro, pero su solución es realmente buena para la forma en que la describí . –