138 votes

Ruby Regexp group matching, assignation de variables sur 1 ligne

J'essaie actuellement de transformer une chaîne de caractères en plusieurs variables. Exemple de chaîne :

ryan_string = "RyanOnRails: This is a test"

Je l'ai fait correspondre avec cette regexp, avec 3 groupes :

ryan_group = ryan_string.scan(/(^.*)(:)(.*)/i)

Maintenant, pour accéder à chaque groupe, je dois faire quelque chose comme ceci :

ryan_group[0][0] (first group) RyanOnRails
ryan_group[0][1] (second group) :
ryan_group[0][2] (third group) This is a test

Cela semble assez ridicule et j'ai l'impression de faire quelque chose de mal. Je m'attendrais à pouvoir faire quelque chose comme ça :

g1, g2, g3 = ryan_string.scan(/(^.*)(:)(.*)/i)

Est-ce possible ? Ou existe-t-il un meilleur moyen que celui que j'utilise actuellement ?

227voto

Lee Jarvis Points 7909

Vous ne voulez pas scan pour cela, car cela n'a guère de sens. Vous pouvez utiliser String#match qui renverra un MatchData vous pouvez alors appeler #captures pour renvoyer un tableau de captures. Quelque chose comme ceci :

#!/usr/bin/env ruby

string = "RyanOnRails: This is a test"
one, two, three = string.match(/(^.*)(:)(.*)/i).captures

p one   #=> "RyanOnRails"
p two   #=> ":"
p three #=> " This is a test"

Sachez que si aucune correspondance n'est trouvée, String#match renverra nil, donc quelque chose comme ceci pourrait mieux fonctionner :

if match = string.match(/(^.*)(:)(.*)/i)
  one, two, three = match.captures
end

Bien que scan n'a guère de sens dans ce contexte. Cela ne l'empêche pas de faire son travail, mais il faut d'abord aplatir l'Array retourné. one, two, three = string.scan(/(^.*)(:)(.*)/i).flatten

48voto

Rado Points 1999

Vous pouvez utiliser Correspondance ou =~ à la place, ce qui vous donnerait une seule correspondance et vous pourriez soit accéder aux données de la même manière, soit utiliser les variables de correspondance spéciales $1, $2, $3.

Quelque chose comme :

if ryan_string =~ /(^.*)(:)(.*)/i
   first = $1
   third = $3
end

35voto

toonsend Points 119

Vous pouvez nommer les correspondances capturées

string = "RyanOnRails: This is a test"
/(?<one>^.*)(?<two>:)(?<three>.*)/i =~ string
puts one, two, three

Cela ne fonctionne pas si vous inversez l'ordre de la chaîne et de la regex.

7voto

Felix Points 477

Vous devez décider si c'est une bonne idée, mais ruby regexp peut (automatiquement) définir des variables locales pour vous !

Je ne sais pas encore si cette fonctionnalité est géniale ou totalement folle, mais votre regex peut définir des variables locales.

ryan_string = "RyanOnRails: This is a test"
/^(?<webframework>.*)(?<colon>:)(?<rest>)/ =~ ryan_string
# This defined three variables for you. Crazy, but true.
webframework # => "RyanOnRails"
puts "W: #{webframework} , C: #{colon}, R: #{rest}"

(Voir http://ruby-doc.org/core-2.1.1/Regexp.html (recherche de "variable locale").

Remarque : Comme indiqué dans un commentaire, je vois qu'il y a une réponse similaire et antérieure à cette question par @toonsend ( https://stackoverflow.com/a/21412455 ). Je ne pense pas avoir "volé", mais si vous voulez être juste avec les éloges et honorer la première réponse, n'hésitez pas :) J'espère qu'aucun animal n'a été blessé.

6voto

Andrew Clark Points 77748

scan() trouvera toutes les correspondances non chevauchantes de la regex dans votre chaîne, donc au lieu de renvoyer un tableau de vos groupes comme vous semblez l'attendre, il renvoie un tableau de tableaux.

Il est probablement préférable d'utiliser match() puis d'obtenir le tableau des captures à l'aide de la fonction MatchData#captures :

g1, g2, g3 = ryan_string.match(/(^.*)(:)(.*)/i).captures

Cependant, vous pouvez également le faire avec scan() si vous le souhaitiez :

g1, g2, g3 = ryan_string.scan(/(^.*)(:)(.*)/i)[0]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X