2010-10-18 8 views
5

Je suis un peu nouveau sur les regex avec Ruby, (ou je suppose que regex en général), mais je me demandais s'il y avait une façon pragmatique de faire correspondre une chaîne à l'aide d'un tableau?Ruby regex correspondant à des chaînes d'un tableau?

Permettez-moi de vous expliquer, que j'ai une liste des ingrédients dans ce cas:

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

En fin de compte je besoin de séparer les ingrédients dans sa « quantité et la mesure » respective et « nom ingrédient », donc comme dans le cas de 2 teaspoons ground cinnamon, sera divisé en "8 ounces et shredded mozzarella cheese

Ainsi, au lieu d'avoir une expression régulière extrêmement longue comme:. (cup\w*|teaspoon\w*ounce\w* .......), comment puis-je utiliser un tableau pour maintenir ces valeurs en dehors de la regex

?

mise à jour

Je l'ai fait (merci 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) 

Cela me donne à ce que je veux, donc je pense que c'est la direction que je veux aller.

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

Répondre

22

Je venais de Personnellement construire l'expression rationnelle programatically, vous pouvez faire :

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

... utilisez l'expression rationnelle.

Tant que vous l'enregistrez et ne continuez pas à le recréer, il devrait être assez efficace.

+7

J'utilise aussi cette approche, avec un petit tweak: Regexp.union (mesures) au lieu de Regexp.new (mesures.join ("|")), même résultat, beaucoup plus propre – Coelhone

3

Pour un tableau un, quelque chose comme cela devrait fonctionner:

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

Par exemple:

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 Merci pour votre réponse, assez curieusement votre réponse est comme pour le bêtise que j'ai décrit mon problème, je ne pense pas que j'étais très clair, mais votre solution est vraiment bonne pour la façon dont je l'ai décrite . –

Questions connexes