Как получить индексы всех вхождений шаблона в строку - PullRequest
11 голосов
/ 25 ноября 2010
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 ]

20 голосов
/ 25 ноября 2010

Вы можете использовать глобальные переменные .scan и $`, что означает Строка слева от последнего успешного совпадения , но она не работает внутри обычного .scan, поэтому вам нужноэто хак (украдено у этот ответ ):

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 - вы получите индекс действительно подобранной части, а не look one:

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"]]
1 голос
/ 04 ноября 2014

Вот модификация ответа Накилона, если вы хотите поместить только массивы "Джека" в массив

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
...