Je me demande comment puis-je obtenir quel modèle dans regex correspond.

J'ai cette regex (j'utilise .match dans Ruby):

(?i)(penalty is\W+[0-9]+\W+night)|(penalty of\W+[0-9]+\W+)

Maintenant, je sais comment renvoyer le texte correspondant dans une chaîne, mais existe-t-il un moyen d'obtenir une chaîne et un modèle correspondants pour cette chaîne? J'aurai donc deux résultats:

  1. Texte correspondant dans la chaîne: la pénalité est de 1 nuit
  2. Motif correspondant: (la pénalité est \ W + [0-9] + \ W + nuit)

Meilleures salutations.

1
Dawid PR 23 nov. 2017 à 18:15

3 réponses

Meilleure réponse
pattern = /(?i)(penalty is\W+[0-9]+\W+night)|(penalty of\W+[0-9]+\W+)/

"penalty of 123 points".match(pattern)
=> #<MatchData "penalty of 123 " 1:nil 2:"penalty of 123 ">

Le nombre de capture non nul révèle quelle partie du modèle correspond. Il existe différentes manières de récupérer cette valeur, telles que:

"penalty of 123 points".match(pattern).captures
=> [nil, "penalty of 123 "]

# Get the index of the first *non-nil* element:
"penalty of 123 points".match(pattern).captures.find_index(&:itself)
=> 1

Ainsi, vous saurez si le premier ou le deuxième groupe correspond, selon que la chaîne de méthodes ci-dessus renvoie 0 ou 1.

Si vous souhaitez rendre ce code un peu plus transparent (plus facile à comprendre comment il fonctionne), vous pouvez également envisager d'utiliser un groupe de capture nommé tel que:

pattern = /(?i)(?<night>penalty is\W+[0-9]+\W+night)|(?<other>penalty of\W+[0-9]+\W+)/

"penalty of 123 points".match(pattern)
=> #<MatchData "penalty of 123 " night:nil other:"penalty of 123 ">

"penalty of 123 points".match(pattern).named_captures
=> {"night"=>nil, "other"=>"penalty of 123 "}

"penalty of 123 points".match(pattern).named_captures.compact.keys.first
=> "other"

Pour aller plus loin, vous pouvez également définir chaque "sous-modèle" comme une expression régulière distincte pour référence future et les joindre pour le match principal, par exemple:

groups = {
  "night" => /(?<night>penalty is\W+[0-9]+\W+night)/i,
  "other" => /(?<other>penalty of\W+[0-9]+\W+)/i
]

pattern = Regexp.union(groups)

match_group_name = "penalty of 123 points".match(pattern).named_captures.compact.keys.first

puts "Pattern that matched: #{groups[match_group_name]}"
3
Tom Lord 23 nov. 2017 à 16:11

Autorisons n'importe quel nombre d'expressions régulières unies et concevons la méthode pour faciliter les tests.

Soit str la chaîne et regexes un tableau des expressions régulières. Pour l'exemple donné dans la question,

regexes = [/(?i)(?<night>penalty is\W+[0-9]+\W+night)/,
           /(?i)(?<other>penalty of\W+[0-9]+\W+)/]

def doit(str, regexes)
  regexes.each do |r|
    m = str[r]
    return [r, m] unless m.nil?
  end
  nil
end
1
Cary Swoveland 23 nov. 2017 à 22:09
REGEXPS = [
  /(?<first>penalty is\W+[0-9]+\W+night)/i,
  /(?<second>penalty of\W+[0-9]+\W+)/i
].freeze

Regexp.union(REGEXPS) =~ ""
$~.named_captures
2
Aleksei Matiushkin 23 nov. 2017 à 15:56
47458660