Comment faire correspondre toutes les occurrences d'une expression régulière
586
Existe-t-il un moyen rapide de trouver chaque correspondance d'une expression régulière dans Ruby? J'ai parcouru l'objet Regex dans la Ruby STL et cherché sur Google en vain.
Mais qu'en est-il de cette affaire? "Match me!". scan (/.../) = ["mat", "ch" "me!" ], mais toutes les occurrences de /.../ seraient ["mat", "atc", "tch", "ch", ...]
Michael Dickens
13
Ce ne serait pas le cas. /.../ est une expression rationnelle gourmande normale. Il ne reviendra pas sur le contenu correspondant. vous pouvez essayer d'utiliser une expression rationnelle paresseuse, mais même cela ne suffira probablement pas. jetez un oeil à la doc regexp ruby-doc.org/core-1.9.3/Regexp.html pour exprimer correctement votre regexp :)
Jean
49
cela ressemble à un Ruby WTF ... pourquoi est-ce sur String au lieu de Regexp avec les autres trucs regexp? Il n'est même pas mentionné nulle part sur les documents pour Regexp
Anentropic
9
Je suppose que c'est parce qu'il est défini et appelé sur String et non sur Regex ... Mais cela a du sens. Vous pouvez écrire une expression régulière pour capturer toutes les correspondances à l'aide de la correspondance Regex # et parcourir les groupes capturés. Ici, vous écrivez une fonction de correspondance partielle et souhaitez qu'elle soit appliquée plusieurs fois sur une chaîne donnée, ce n'est pas la responsabilité de Regexp. Je vous suggère de vérifier l'implémentation du scan pour une meilleure compréhension: ruby-doc.org/core-1.9.3/String.html#method-i-scan
Jean
9
@MichaelDickens: Dans ce cas, vous pouvez utiliser /(?=(...))/.
Konrad Borowski
67
Pour trouver toutes les chaînes correspondantes, utilisez la scanméthode String .
str.scan(/\d+[m-t]/) # => ["54m", "1t", "3r"]est plus idiomatique questr.to_enum(:scan,re).map {$&}
le Tin Man
Vous avez peut-être mal compris. L'expression régulière de l'exemple d'un utilisateur auquel j'ai répondu était: /(\d+)[m-t]/ne pas /\d+[m-t]/écrire: re = /(\d+)[m-t]/; str.scan(re)c'est la même chose str.scan(/(\d+)[mt]/)mais j'obtiens #> [["" 54 "], [" 1 "], [" 3 "]]et non "54m", "1t", "3r"]La question était: si j'ai une expression régulière avec un groupe et que je veux capturer tous les modèles sans changer le régulier expression (quitter le groupe), comment faire? En ce sens, une solution possible, quoique un peu cryptique et difficile à lire, était:str.to_enum(:scan,re).map {$&}
MVP
-1
Vous pouvez utiliser string.scan(your_regex).flatten. Si votre expression régulière contient des groupes, elle reviendra dans un seul tableau simple.
Supprimez le regroupement your_regex = /(\d+)[m-t]/et vous n'aurez pas besoin de l'utiliser flatten. Votre dernier exemple utilise last_matchqui, dans ce cas, est probablement sûr, mais est global et pourrait éventuellement être écrasé si une expression rationnelle était mise en correspondance avant l'appel last_match. Au lieu de cela, il est probablement plus sûr à utiliser string.match(regex).captures # => ["group_photo", "jpg"]ou string.scan(/\d+/) # => ["54", "3", "1", "7", "3", "0"]comme indiqué dans d'autres réponses, selon le modèle et les besoins.
Réponses:
L'utilisation
scan
devrait faire l'affaire:la source
/(?=(...))/
.Pour trouver toutes les chaînes correspondantes, utilisez la
scan
méthode String .Si vous le souhaitez,
MatchData
qui est le type de l'objet renvoyé par lamatch
méthode Regexp , utilisez:L'avantage d'utiliser
MatchData
est que vous pouvez utiliser des méthodes telles queoffset
:Consultez ces questions si vous souhaitez en savoir plus:
La lecture sur les variables spéciales
$&
,$'
,$1
,$2
Ruby sera utile aussi.la source
si vous avez une expression rationnelle avec des groupes:
vous pouvez utiliser la
scan
méthode de String pour trouver des groupes correspondants:Pour trouver le motif correspondant:
la source
str.scan(/\d+[m-t]/) # => ["54m", "1t", "3r"]
est plus idiomatique questr.to_enum(:scan,re).map {$&}
/(\d+)[m-t]/
ne pas/\d+[m-t]/
écrire:re = /(\d+)[m-t]/; str.scan(re)
c'est la même chosestr.scan(/(\d+)[mt]/)
mais j'obtiens #>[["" 54 "], [" 1 "], [" 3 "]]
et non"54m", "1t", "3r"]
La question était: si j'ai une expression régulière avec un groupe et que je veux capturer tous les modèles sans changer le régulier expression (quitter le groupe), comment faire? En ce sens, une solution possible, quoique un peu cryptique et difficile à lire, était:str.to_enum(:scan,re).map {$&}
Vous pouvez utiliser
string.scan(your_regex).flatten
. Si votre expression régulière contient des groupes, elle reviendra dans un seul tableau simple.Regex peut également être un groupe nommé.
Vous pouvez également utiliser
gsub
, c'est juste une autre façon si vous voulez MatchData.la source
your_regex = /(\d+)[m-t]/
et vous n'aurez pas besoin de l'utiliserflatten
. Votre dernier exemple utiliselast_match
qui, dans ce cas, est probablement sûr, mais est global et pourrait éventuellement être écrasé si une expression rationnelle était mise en correspondance avant l'appellast_match
. Au lieu de cela, il est probablement plus sûr à utiliserstring.match(regex).captures # => ["group_photo", "jpg"]
oustring.scan(/\d+/) # => ["54", "3", "1", "7", "3", "0"]
comme indiqué dans d'autres réponses, selon le modèle et les besoins.