Подтвердить что ты не робот

Возвращаемый индекс всех вхождений символа в строку в рубине

Я пытаюсь вернуть индекс ко всем вхождениям определенного символа в строке с использованием Ruby. Строка примера "a#asg#sdfg#d##" и ожидаемый возврат [1,5,10,12,13] при поиске символов #. Следующий код выполняет эту работу, но должен быть более простой способ сделать это?

def occurances (line)

  index = 0
  all_index = []

  line.each_byte do |x|
    if x == '#'[0] then
      all_index << index
    end
    index += 1
  end

  all_index
end
4b9b3361

Ответ 1

s = "a#asg#sdfg#d##"
a = (0 ... s.length).find_all { |i| s[i,1] == '#' }

Ответ 2

require 'enumerator' # Needed in 1.8.6 only
"1#3#a#".enum_for(:scan,/#/).map { Regexp.last_match.begin(0) }
#=> [1, 3, 5]

ETA: Это работает, создавая Enumerator, который использует scan(/#/) как свой каждый метод.

Сканирование

дает каждое появление указанного шаблона (в данном случае /#/), а внутри блока вы можете вызвать Regexp.last_match для доступа к объекту MatchData для соответствия.

MatchData#begin(0) возвращает индекс, где начинается совпадение, и поскольку мы использовали карту в перечислителе, мы возвращаем массив этих индексов.

Ответ 3

Здесь менее привлекательный способ:

i = -1
all = []
while i = x.index('#',i+1)
  all << i
end
all

В тесте быстрой скорости это было примерно в 3,3 раза быстрее, чем метод FM find_all, и примерно в 2,5 раза быстрее, чем метод sepp2k enum_for.

Ответ 4

Здесь длинная цепочка методов:

"a#asg#sdfg#d##".
  each_char.
  each_with_index.
  inject([]) do |indices, (char, idx)|
    indices << idx if char == "#"
    indices
  end

# => [1, 5, 10, 12, 13]

требуется 1.8.7 +

Ответ 5

Другое решение, полученное из ответа FM:

s = "a#asg#sdfg#d##"
q = []
s.length.times {|i| q << i if s[i,1] == '#'}

Мне нравится, что Ruby никогда не имеет только одного способа сделать что-то!