Как получить данные соответствия для всех вхождений регулярного выражения Ruby в строку?
Мне нужно MatchData
для каждого вхождения регулярного выражения в строку. Это отличается от метода сканирования, предложенного в Match All Occurrences of Regex, так как это дает мне только массив строк (мне нужно полное MatchData, чтобы начать и конечная информация и т.д.).
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)
Я подозреваю, что есть какой-то метод, который я забыл. Предложения?
Ответы
Ответ 1
Вы хотите
"abc12def34ghijklmno567pqrs".to_enum(:scan, /\d+/).map { Regexp.last_match }
который дает вам
[#<MatchData "12">, #<MatchData "34">, #<MatchData "567">]
"Трюк", как вы видите, построил перечислитель, чтобы получить каждый last_match.
Ответ 2
Мое текущее решение заключается в добавлении метода 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
Теперь я могу сделать:
numbers.each_match input do |match|
puts "Found #{match[0]} at #{match.begin(0)} until #{match.end(0)}"
end
Скажите, что есть лучший способ.
Ответ 3
Поместите это здесь на всякий случай, чтобы сделать код доступным через соответствующий поиск google:
input = "abc12def34ghijklmno567pqrs"
numbers = /\d+/
input.gsub(numbers) { |m| p $~ }
Результат такой же, как и ожидалось:
⇒ #<MatchData "12">
⇒ #<MatchData "34">
⇒ #<MatchData "567">
Подробное объяснение.
Ответ 4
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">]
Ответ 5
Я удивлен, что никто не упомянул удивительный StringScanner класс, включенный в стандартную библиотеку 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
Нет, это не дает вам объекты MatchData, но это дает вам интерфейс с индексами в строку.