44 votes

Comment obtenir les données de correspondance pour toutes les occurrences d'une expression régulière Ruby dans une chaîne ?

J'ai besoin du MatchData pour chaque occurrence d'une expression régulière dans une chaîne. Ceci est différent de la méthode d'analyse suggérée dans Match All Occurrences of a Regex , car cela ne me donne qu'un tableau de chaînes (j'ai besoin du MatchData complet, pour obtenir les informations de début et de fin, etc.).

 input = "abc12def34ghijklmno567pqrs"
numbers = /\d+/

numbers.match input # #<MatchData "12"> (only the first match)
input.scan numbers  # ["12", "34", "567"] (all matches, but only the strings)

Je soupçonne qu'il y a une méthode que j'ai oubliée. Suggestions?

74voto

i-blis Points 1733

Vous voulez

 "abc12def34ghijklmno567pqrs".to_enum(:scan, /\d+/).map { Regexp.last_match }

qui vous donne

 [#<MatchData "12">, #<MatchData "34">, #<MatchData "567">] 

Le "truc" est, comme vous le voyez, de construire un énumérateur afin d'obtenir chaque last_match .

9voto

Joshua Flanagan Points 5907

Ma solution actuelle consiste à ajouter une each_match à Regexp :

 class Regexp
  def each_match(str)
    start = 0
    while matchdata = self.match(str, start)
      yield matchdata
      start = matchdata.end(0)
    end
  end
end

Maintenant je peux faire :

 numbers.each_match input do |match|
  puts "Found #{match[0]} at #{match.begin(0)} until #{match.end(0)}"
end

Dis-moi qu'il y a un meilleur moyen.

8voto

mudasobwa Points 5530

Je vais le mettre ici pour rendre le code disponible via une recherche :

 input = "abc12def34ghijklmno567pqrs"
numbers = /\d+/
input.gsub(numbers) { |m| p $~ }

Le résultat est comme demandé :

 ⇒ #<MatchData "12">
⇒ #<MatchData "34">
⇒ #<MatchData "567">

Voir " input.gsub(numbers) { |m| p $~ } Correspondance des données dans Ruby pour toutes les occurrences d'une chaîne " pour plus d'informations.

3voto

mwp Points 430

Je suis surpris que personne n'ait mentionné l'incroyable classe StringScanner incluse dans la bibliothèque standard de Ruby :

 require 'strscan'

s = StringScanner.new('abc12def34ghijklmno567pqrs')

while s.skip_until(/\d+/)
  num, offset = s.matched.to_i, [s.pos - s.matched_size, s.pos - 1]

  # ..
end

Non, cela ne vous donne pas les objets MatchData, mais cela vous donne une interface basée sur un index dans la chaîne.

0voto

Lyndon S Points 271
input = "abc12def34ghijklmno567pqrs"
n = Regexp.new("\\d+")
[n.match(input)].tap { |a| a << n.match(input,a.last().end(0)+1) until a.last().nil? }[0..-2]

=> [#<MatchData "12">, #<MatchData "34">, #<MatchData "567">]

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