Как получить индексы всех вхождений шаблона в строке
string = "Jack and Jill went up the hill to fetch a pail of water. Jack fell down and broke his crown. And Jill came tumbling after. "
d = string.match(/(jack|jill)/i) # -> MatchData "Jill" 1:"Jill"
d.size # -> 1
Это соответствует только первому вхождению.string.scan
выполняет задание частично, но ничего не говорит об индексе совпадающего шаблона.
Как получить список всех совпадающих экземпляров шаблона и их индексов (позиций)?
2 ответов
можно использовать .scan
и $`
глобальная переменная, что означает строка слева от последнего успешного матча, но он не работает внутри обычного .scan
, Так что вам нужно, это hack (похищенных из ответ):
string = "Jack and Jill went up the hill to fetch a pail of water. Jack fell down and broke his crown. And Jill came tumbling after. "
string.to_enum(:scan, /(jack|jill)/i).map do |m,|
p [$`.size, m]
end
выход:
[0, "Jack"]
[9, "Jill"]
[57, "Jack"]
[97, "Jill"]
UPD:
обратите внимание на поведение lookbehind - вы получаете индекс действительно совпадающей части, а не посмотреть один:
irb> "ab".to_enum(:scan, /ab/ ).map{ |m,| [$`.size, $~.begin(0), m] }
=> [[0, 0, "ab"]]
irb> "ab".to_enum(:scan, /(?<=a)b/).map{ |m,| [$`.size, $~.begin(0), m] }
=> [[1, 1, "b"]]
вот модификация ответа Nakilon, если вы хотите поместить только местоположения "Jack" в массив
location_array = Array.new
string = "Jack and Jack went up the hill to fetch a pail of Jack..."
string.to_enum(:scan,/(jack)/i).map do |m,|
location_array.push [$`.size]
end