Обычно я определяю правило для end_of_line. Это основано на трюке в http://kschiess.github.io/parslet/tricks.html для сопоставления конец_файла.
class MyParser < Parslet::Parser
rule(:cr) { str("\n") }
rule(:eol?) { any.absent? | cr }
rule(:line_body) { (eol?.absent? >> any).repeat(1) }
rule(:line) { cr | line_body >> eol? }
rule(:lines?) { line.repeat (0)}
root(:lines?)
end
puts MyParser.new.parse(""" this is a line
so is this
that was too
This ends""").inspect
Очевидно, что если вы хотите сделать с парсером больше, чем вы можете сделать с помощью String::split("\n"), вы замените line_body
чем-то полезным :)
Я поторопился с ответом на этот вопрос и заморочился. Я просто хотел объяснить ошибку, которую я сделал, и показать вам, как избежать ошибок такого рода.
Вот мой первый ответ.
rule(:eol) { str('\n') | any.absent? }
rule(:line) { (eol.absent? >> any).repeat >> eol }
rule(:lines) { line.as(:line).repeat }
Я не следовал своим обычным правилам:
- Всегда указывайте количество повторов явным образом
- Любое правило, которое может соответствовать строкам нулевой длины, должно иметь имя, оканчивающееся на '?'
Итак, давайте применим эти...
rule(:eol?) { str('\n') | any.absent? }
# as the second option consumes nothing
rule(:line?) { (eol.absent? >> any).repeat(0) >> eol? }
# repeat(0) can consume nothing
rule(:lines?) { line.as(:line?).repeat(0) }
# We have a problem! We have a rule that can consume nothing inside a `repeat`!
Вот посмотрите, почему мы получаем бесконечный цикл. По мере потребления ввода вы получаете только end of file
, что соответствует eol?
и, следовательно, line?
(поскольку тело строки может быть пустым). Находясь внутри lines
' repeat
, он продолжает сопоставляться, ничего не потребляя, и зацикливается навсегда.
Нам нужно изменить линейное правило, чтобы оно всегда что-то потребляло.
rule(:cr) { str('\n') }
rule(:eol?) { cr | any.absent? }
rule(:line_body) { (eol.absent? >> any).repeat(1) }
rule(:line) { cr | line_body >> eol? }
rule(:lines?) { line.as(:line).repeat(0) }
Теперь line
должно соответствовать чему-то, либо cr
(для пустых строк), либо хотя бы одному символу, за которым следует необязательный eol?
. У всех repeat
есть тела, которые что-то потребляют. Теперь мы золотые.
person
Nigel Thorne
schedule
24.07.2013