Вы можете сделать следующее.
str = 'line:xss /* */ /* /* CODE_Comment */ '
str.gsub(/\/\*/).with_object([]) { |_,a| a << [Regexp.last_match.begin(0), 's'] }
#=> [[9, "s"], [19, "s"], [24, "s"]]
Шаги следующие:
enum1 = str.gsub(/\/\*/)
#=> #<Enumerator: "line:xss /* */ /* /* CODE_Comment */ "
# :gsub(/\/\*/)>
Если выИзучите документ для String # gsub . Вы увидите, что когда gsub
имеет один аргумент и не имеет блока (форма метода 4 th ), он возвращает перечислитель.Любопытно, что при таком способе он не имеет ничего общего с заменой подстрок другими подстроками.
enum1
не делает ничего, кроме генерации совпадений:
enum1.next #=> "/*"
enum1.next #=> "/*"
enum1.next #=> "/*"
enum1.next #=> StopIteration (iteration reached an end)
См. Enumerator #следующий .Прежде чем продолжить, давайте сбросим перечислитель:
enum1.rewind
См. Перечислитель # перемотка .Затем
enum2 = enum1.with_object([])
#=> #<Enumerator: #<Enumerator: "line:xss /* */ /* /* CODE_Comment */ "
# :gsub(/\/\*/)>:with_object([])>
enum2.next #=> ["/*", []]
enum2.next #=> ["/*", []]
enum2.next #=> ["/*", []]
enum2.next #=> StopIteration (iteration reached an end)
enum2.rewind
enum2
(который можно рассматривать как составной перечислитель ) теперь генерирует элементы, которые он передает блоку.Значения этих элементов фиксируются переменными блока, а затем выполняется расчет блока.Мы можем добавить несколько операторов puts
, чтобы проверить вычисляемые значения.
enum2.each do |_,a|
puts "\n_ = #{_}, a = #{a}"
md = Regexp.last_match
b= md.begin(0)
puts "md = #{md}, b = #{b}"
a << [b, 's']
puts "a = #{a}"
end
#=> [[9, "s"], [19, "s"], [24, "s"]]
и распечатать
_ = /*, a = []
md = /*, b = 9
a = [[9, "s"]]
_ = /*, a = [[9, "s"]]
md = /*, b = 19
a = [[9, "s"], [19, "s"]]
_ = /*, a = [[9, "s"], [19, "s"]]
md = /*, b = 24
a = [[9, "s"], [19, "s"], [24, "s"]]
Я использовал подчеркивание (допустимая локальная переменная) в качестве заполнителядля первой переменной блока, чтобы показать читателю, что она не используется в вычислении блока (обычно используемое соглашение).Для построения массива нам понадобится смещение в строке str
, где это совпадение было сделано.Для этого мы сначала получаем экземпляр MatchData
, сгенерированный этим соответствием (см. Regexp :: last_match ), а затем используем метод LastMatch # begin , чтобы получить смещение для началаматч.Наконец, мы добавляем желаемый массив из 2 элементов к a
.
Значение Regexp.last_match
хранится в глобальной переменной $~
, так что эта переменная иногда используется вместо Regexp.last_match
.