Я разделяю потенциально большую строку (скажем, 20 МБ, хотя это совершенно произвольно) на токены, определенные списком регулярных выражений.
Мой текущий алгоритм использует следующий подход:
- Все регулярные выражения оптимизированы, чтобы иметь утверждение нулевой ширины
^
в начале их
- Для каждого регулярного выражения в списке я пытаюсь
#slice!
строка ввода
- Если мы
#slice!
что-нибудь получим, мы получим совпадение И входная строка была готова для поиска следующего токена (поскольку #slice!
изменяет строку)
К сожалению, это медленно, что связано с повторением #slice!
на длинной строке ... похоже, что изменение больших строк в ruby не быстро.
Так что мне интересно, есть ли способ сопоставить мои регулярные выражения новой подстроке (то есть оставшейся части строки) без ее изменения?
Текущий алгоритм в (проверенном, работающем) псевдокоде:
rules = {
:foo => /^foo/,
:bar => /^bar/,
:int => /^[0-9]+/
}
input = "1foofoo23456bar1foo"
# or if you want your computer to cry
# input = "1foofoo23456bar1foo" * 1_000_000
tokens = []
until input.length == 0
matched = rules.detect do |(name, re)|
if match = input.slice!(re)
tokens << { :rule => name, :value => match }
end
end
raise "Uncomsumed input: #{input}" unless matched
end
pp tokens
# =>
[{:rule=>:int, :value=>"1"},
{:rule=>:foo, :value=>"foo"},
{:rule=>:foo, :value=>"foo"},
{:rule=>:int, :value=>"23456"},
{:rule=>:bar, :value=>"bar"},
{:rule=>:int, :value=>"1"},
{:rule=>:foo, :value=>"foo"}]
Обратите внимание, что хотя простое сопоставление регулярных выражений со строкой эквивалентное количество раз не является быстрым ни при каких условиях, оно не настолько медленное, чтобы у вас было время приготовить пиццу, пока вы ждете (несколько секунд против много много минут).