Обычно я определяю правило для end_of_line. Это основано на трюке в http://kschiess.github.io/parslet/tricks.html для соответствия end_of_file.
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
Очевидно, что если вы хотите сделать больше с анализатором, чем вы можете достичь с Последовательностью :: разделенного («\ п») вы замените line_body
с чем-то полезным :)
I быстро перешел к ответу на этот вопрос и удалил его. Я просто объясню, что я сделал, и покажу вам, как избежать ошибок такого рода.
Вот мой первый ответ.
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
имеют тела, которые что-то потребляют. Мы теперь золотые.
Это похоже на приятное решение. Мое обходное решение заключалось в том, чтобы работать с '\ n', а также добавить новую строку для входящей строки, чтобы предотвратить сбой соответствия в конце. Однако это выглядит чище. Благодаря! – Danyel