Модуль Ruby's Abbrev
является хорошей отправной точкой.Он разбивает строку на хеш, состоящий из уникальных ключей, которые могут идентифицировать полное слово:
require 'abbrev'
require 'pp'
abbr = Abbrev::abbrev(['ruby'])
>> {"rub"=>"ruby", "ru"=>"ruby", "r"=>"ruby", "ruby"=>"ruby"}
Для каждого нажатия клавиши вы можете выполнить поиск и посмотреть, есть ли совпадение.Я бы отфильтровал все ключи короче определенной длины, чтобы уменьшить размер хеша.
Ключи также дадут вам быстрый набор слов для поиска совпадений подслов в вашей исходной строке.
Для быстрого поиска, чтобы увидеть, есть ли совпадение подстроки:
regexps = Regexp.union(
abbr.keys.sort.reverse.map{ |k|
Regexp.new(
Regexp.escape(k),
Regexp::IGNORECASE
)
}
)
Обратите внимание, что он экранирует шаблоны, которые позволяют вводить символы, такие как ?
, *
или .
, и будут рассматриваться как литералы, а не специальные символы для регулярных выражений, как они обычно обрабатываются.
Результат выглядит так:
/(?i-mx:ruby)|(?i-mx:rub)|(?i-mx:ru)|(?i-mx:r)/
Регулярное выражение match
будетвернуть информацию о том, что было найдено.
Поскольку union
«ИЛИ» паттернов, он найдет только первое совпадение, которое будет самым коротким вхождением в строке.Чтобы исправить это, переверните сортировку.
Это должно дать вам хорошее начало в том, что вы хотите сделать.
РЕДАКТИРОВАТЬ: Вот код, чтобы прямо ответить на вопрос.Мы были заняты на работе, поэтому потребовалось несколько дней, чтобы вернуть это:
require 'abbrev'
require 'pp'
abbr = Abbrev::abbrev(['ruby'])
regexps = Regexp.union( abbr.keys.sort.reverse.map{ |k| Regexp.new( Regexp.escape(k), Regexp::IGNORECASE ) } )
target_str ='Ruby rocks, rub-a-dub-dub, RU there?'
str_offset = 0
offsets = []
loop do
match_results = regexps.match(target_str, str_offset)
break if (match_results.nil?)
s, e = match_results.offset(0)
offsets << [s, e - s]
str_offset = 1 + s
end
pp offsets
>> [[0, 4], [5, 1], [12, 3], [27, 2], [33, 1]]
Если вы хотите, чтобы диапазоны заменили offsets << [s, e - s]
на offsets << [s .. e]
, который вернет:
>> [[0..4], [5..6], [12..15], [27..29], [33..34]]