Я хочу получить индекс, а также результаты сканирования
"abab".scan(/a/)
Я хотел бы иметь не только
=> ["a", "a"]
но также индекс этих совпадений
[1, 3]
любое предложение?
Я хочу получить индекс, а также результаты сканирования
"abab".scan(/a/)
Я хотел бы иметь не только
=> ["a", "a"]
но также индекс этих совпадений
[1, 3]
любое предложение?
Попробуйте следующее:
res = []
"abab".scan(/a/) do |c|
res << [c, $~.offset(0)[0]]
end
res.inspect # => [["a", 0], ["a", 2]]
Здесь нужно искать, в зависимости от поведения, которое вы ожидаете.
Если вы ищете /dad/
в "dadad"
, вы получите только [["dad",0]]
, потому что scan
продвигается к концу каждого совпадения, когда находит его (что неправильно для меня).
Я придумал эту альтернативу:
def scan_str(str, pattern)
res = []
(0..str.length).each do |i|
res << [Regexp.last_match.to_s, i] if str[i..-1] =~ /^#{pattern}/
end
res
end
Если бы вы хотели, вы могли бы сделать аналогичную вещь с StringScanner из стандартной библиотеки, это может быть быстрее для длинных строк.
Очень похоже на то, что сказал @jim и работает немного лучше для более длинных строк:
def matches str, pattern
arr = []
while (str && (m = str.match pattern))
offset = m.offset(0).first
arr << offset + (arr[-1] ? arr[-1] + 1 : 0)
str = str[(offset + 1)..-1]
end
arr
end
Я удивился, что нет метода, подобного String#scan
, который возвращает массив объектов MatchData
, аналогичный String#match
. Итак, если вам нравится перехват обезьян, вы можете комбинировать это с решением Тодда (Enumerator
введен в 1.9):
class Regexp
def scan str
Enumerator.new do |y|
str.scan(self) do
y << Regexp.last_match
end
end
end
end
#=> nil
/a/.scan('abab').map{|m| m.offset(0)[0]}
#=> [0, 2]