Получить индекс результатов сканирования строки в ruby - PullRequest
13 голосов
/ 19 августа 2010

Я хочу получить индекс, а также результаты сканирования

"abab".scan(/a/)

Я хотел бы иметь не только

=> ["a", "a"]

, но и индекс этих совпадений

[1, 3]

есть предложения?

Ответы [ 4 ]

23 голосов
/ 19 августа 2010

Попробуйте это:

res = []
"abab".scan(/a/) do |c|
  res << [c, $~.offset(0)[0]]
end

res.inspect # => [["a", 0], ["a", 2]]
6 голосов
/ 04 декабря 2010

Здесь стоит обратить внимание, в зависимости от ожидаемого поведения.

Если вы ищете /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 из стандартной библиотеки, это может быть быстрее для длинных строк.

4 голосов
/ 22 июля 2015

Очень похоже на то, что сказал @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
1 голос
/ 19 августа 2010

Меня удивило, что не существует метода, подобного 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]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...