J'ai besoin de 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 toutes les occurrences d'un regex , car cela ne me donne qu'un tableau de chaînes (j'ai besoin de l'intégralité de MatchData 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 négligée. Suggestions?
Tu veux
"abc12def34ghijklmno567pqrs".to_enum(:scan, /\d+/).map { Regexp.last_match }
qui te donne
[#<MatchData "12">, #<MatchData "34">, #<MatchData "567">]
Le "truc" consiste, comme vous le voyez, à construire un énumérateur afin d’obtenir chaque last_match.
Ma solution actuelle consiste à ajouter une méthode 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, il y a un meilleur moyen.
Je le mettrai ici au cas où le code serait disponible via la recherche Google correspondante:
input = "abc12def34ghijklmno567pqrs"
numbers = /\d+/
input.gsub(numbers) { |m| p $~ }
Le résultat est tel que demandé:
⇒ #<MatchData "12">
⇒ #<MatchData "34">
⇒ #<MatchData "567">
Je suis surpris que personne n'ait mentionné l'étonnant StringScanner class inclus 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.
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">]