Как узнать начальную точку для каждого матча в рубине

Скажем, у меня есть следующая строка

string = "#Sachin is Indian cricketer. #Tendulkar is right hand batsman. #Sachin has been honoured with the Padma Vibhushan award "

Я хочу o/p как

"#Sachin|0|7;#Tendulkar|29|10;#Sachinn|63|7;"

Я пробовал следовать

 new_string = ""
 string.scan(/#\S+/).each{|match| new_string+="#{match}|#{string.index(match)}|#{match.length};"  }

который дает мне

 "#Sachin|0|7;#Tendulkar|29|10;#Sachin|0|7;" 

Итак, как я получу начальный индекс каждой подстроки?

Ответ 1

Это на самом деле довольно нетривиальная задача, и она была обсуждена совсем в других вопросах о SO. Это наиболее распространенное решение:

string = "#Sachin is Indian cricketer. #Tendulkar is right hand batsman. #Sachin has been honoured with the Padma Vibhushan award "
new_string = string.to_enum(:scan,/#\S+/i).inject(''){|s,m| s + "#{m}|#{$`.size}|#{m.length};"}

Ответ 2

На основе этой темы Как получить данные соответствия для всех вхождений регулярного выражения Ruby в строку? просто быстрый пример:

string = "#Sachin is Indian cricketer. #Tendulkar is right hand batsman. #Sachin has been honoured with the Padma Vibhushan award "
new_string = ""
string
  .to_enum(:scan, /#\S+/)
  .each do |wrd|
    m = Regexp.last_match
    new_string += "#{wrd}|#{m.offset(0)[0]}|#{wrd.length};"
  end
p new_string

Ответ 3

Здесь используется сканирование:

offset = 0
string.scan(/(#\S*)([^#]*)/).map{|m| v = "#{m[0]}|#{offset}|#{m[0].length};"; offset += m.join.length; v}.join
#=> "#Sachin|0|7;#Tendulkar|29|10;#Sachin|63|7;"