解析markdown缩进代码块

时间:2015-05-27 14:21:45

标签: ruby parsing markdown parslet

我正在尝试使用Parslet编写的语法来解析Markdown。但是,我无法通过缩进的代码块,因为我到目前为止尝试的所有东西都被卡在递归中。它们看起来像这样:

    This is a indented code block.
    Second line.

    Code block continues after blank line.

    There can be any number of chunks, 
    separated by not more than one blank line.

为了解决这个问题,我写了一个最小的例子,它用\n替换行(包括a)和用空格替换空行(\n\n),例如:{{1} }。

a aaa aa

正常运行# recurring_group_parser.rb require 'parslet' require 'rspec' require 'parslet/rig/rspec' class RecurringGroupParser < Parslet::Parser root(:block) rule :block do chunk.repeat(1,3) end rule :chunk do str('a').repeat(1,3) >> space end rule :space do str(' ') | chunk.absent? end end describe RecurringGroupParser do it 'should parse a' do is_expected.to parse "a" end it 'should parse aa' do is_expected.to parse "aa" end it 'should parse aaa' do is_expected.to parse "aaa" end it 'should parse a a' do is_expected.to parse "a a" end it 'should parse aa a' do is_expected.to parse "aa a" end it 'should parse aaa a' do is_expected.to parse "aaa a" end it 'should parse a aa' do is_expected.to parse "a aa" end it 'should parse a aaa' do is_expected.to parse "a aaa" end it 'should parse aa a' do is_expected.to parse "aa a" end it 'should parse aa aa' do is_expected.to parse "aa aa" end it 'should parse aa aaa' do is_expected.to parse "aa aaa" end it 'should parse aaa aa' do is_expected.to parse "aaa aa" end it 'should parse aaa aaa' do is_expected.to parse "aaa aaa" end it 'should parse a a a' do is_expected.to parse "a a a" end it 'should parse aa a a' do is_expected.to parse "aa a a" end it 'should parse aaa a a' do is_expected.to parse "aaa a a" end it 'should parse a aa a' do is_expected.to parse "a aa a" end it 'should parse aa aa a' do is_expected.to parse "aa aa a" end it 'should parse aaa aa a' do is_expected.to parse "aaa aa a" end it 'should parse a aaa a' do is_expected.to parse "a aaa a" end it 'should parse aa aaa a' do is_expected.to parse "aa aaa a" end it 'should parse aaa aaa a' do is_expected.to parse "aaa aaa a" end it 'should parse a a aa' do is_expected.to parse "a a aa" end it 'should parse aa a aa' do is_expected.to parse "aa a aa" end it 'should parse aaa a aa' do is_expected.to parse "aaa a aa" end it 'should parse a aa aa' do is_expected.to parse "a aa aa" end it 'should parse aa aa aa' do is_expected.to parse "aa aa aa" end it 'should parse aaa aa aa' do is_expected.to parse "aaa aa aa" end it 'should parse a aaa aa' do is_expected.to parse "a aaa aa" end it 'should parse aa aaa aa' do is_expected.to parse "aa aaa aa" end it 'should parse aaa aaa aa' do is_expected.to parse "aaa aaa aa" end it 'should parse a a aaa' do is_expected.to parse "a a aaa" end it 'should parse aa a aaa' do is_expected.to parse "aa a aaa" end it 'should parse aaa a aaa' do is_expected.to parse "aaa a aaa" end it 'should parse a aa aaa' do is_expected.to parse "a aa aaa" end it 'should parse aa aa aaa' do is_expected.to parse "aa aa aaa" end it 'should parse aaa aa aaa' do is_expected.to parse "aaa aa aaa" end it 'should parse a aaa aaa' do is_expected.to parse "a aaa aaa" end it 'should parse aa aaa aaa' do is_expected.to parse "aa aaa aaa" end it 'should parse aaa aaa aaa' do is_expected.to parse "aaa aaa aaa" end end 。只有当我把新行重新放入时,才会停滞不前:

rspec recurring_group_parser.rb

为了简化这一点,行只能由单个# recurring_group_parser.rb require 'parslet' require 'rspec' require 'parslet/rig/rspec' class RecurringGroupParser < Parslet::Parser root(:block) rule :block do chunk.repeat(1,3) end rule :chunk do line.repeat(1,3) >> blank_line end rule :line do str('a') >> newline end rule :blank_line do newline.repeat(2) | chunk.absent? end rule :newline do str("\n") | any.absent? end end describe RecurringGroupParser do it 'should parse a' do is_expected.to parse "a" end it 'should parse aa' do is_expected.to parse "a\na" end it 'should parse aaa' do is_expected.to parse "a\na\na" end it 'should parse a a' do is_expected.to parse "a\n\na" end it 'should parse aa a' do is_expected.to parse "a\na\n\na" end it 'should parse aaa a' do is_expected.to parse "a\naa\n\na" end it 'should parse a aa' do is_expected.to parse "a\n\na\na" end it 'should parse a aaa' do is_expected.to parse "a\n\na\na\na" end it 'should parse aa a' do is_expected.to parse "a\na\n\na" end it 'should parse aa aa' do is_expected.to parse "a\na\n\na\na" end it 'should parse aa aaa' do is_expected.to parse "a\na\n\na\na\na" end it 'should parse aaa aa' do is_expected.to parse "a\naa\n\na\na" end it 'should parse aaa aaa' do is_expected.to parse "a\naa\n\na\na\na" end it 'should parse a a a' do is_expected.to parse "a\n\na\n\na" end it 'should parse aa a a' do is_expected.to parse "a\na\n\na\n\na" end it 'should parse aaa a a' do is_expected.to parse "a\naa\n\na\n\na" end it 'should parse a aa a' do is_expected.to parse "a\n\na\na\n\na" end it 'should parse aa aa a' do is_expected.to parse "a\na\n\na\na\n\na" end it 'should parse aaa aa a' do is_expected.to parse "a\naa\n\na\na\n\na" end it 'should parse a aaa a' do is_expected.to parse "a\n\na\naa\n\na" end it 'should parse aa aaa a' do is_expected.to parse "a\na\n\na\naa\n\na" end it 'should parse aaa aaa a' do is_expected.to parse "a\naa\n\na\naa\n\na" end it 'should parse a a aa' do is_expected.to parse "a\n\na\n\na\na" end it 'should parse aa a aa' do is_expected.to parse "a\na\n\na\n\na\na" end it 'should parse aaa a aa' do is_expected.to parse "a\naa\n\na\n\na\na" end it 'should parse a aa aa' do is_expected.to parse "a\n\na\na\n\na\na" end it 'should parse aa aa aa' do is_expected.to parse "a\na\n\na\na\n\na\na" end it 'should parse aaa aa aa' do is_expected.to parse "a\naa\n\na\na\n\na\na" end it 'should parse a aaa aa' do is_expected.to parse "a\n\na\naa\n\na\na" end it 'should parse aa aaa aa' do is_expected.to parse "a\na\n\na\naa\n\na\na" end it 'should parse aaa aaa aa' do is_expected.to parse "a\naa\n\na\naa\n\na\na" end it 'should parse a a aaa' do is_expected.to parse "a\n\na\n\na\na\na" end it 'should parse aa a aaa' do is_expected.to parse "a\na\n\na\n\na\na\na" end it 'should parse aaa a aaa' do is_expected.to parse "a\naa\n\na\n\na\na\na" end it 'should parse a aa aaa' do is_expected.to parse "a\n\na\na\n\na\na\na" end it 'should parse aa aa aaa' do is_expected.to parse "a\na\n\na\na\n\na\na\na" end it 'should parse aaa aa aaa' do is_expected.to parse "a\naa\n\na\na\n\na\na\na" end it 'should parse a aaa aaa' do is_expected.to parse "a\n\na\naa\n\na\na\na" end it 'should parse aa aaa aaa' do is_expected.to parse "a\na\n\na\naa\n\na\na\na" end it 'should parse aaa aaa aaa' do is_expected.to parse "a\naa\n\na\naa\n\na\na\na" end end 组成,并且不会缩进,但可以在以后轻松更改,与无法完成解析无关。我也非常确定a中的chunk.absent?rule :blank_line中的any.absent?之间存在冲突,但我不知道如何解决此问题并提供打破递归的标准。任何需要的帮助!

1 个答案:

答案 0 :(得分:2)

在这种情况下,换行可以是eof。在哪种情况下换行。 repeat(2)重复匹配eof。你想要“重复(2,2)”。您可以轻松找到这些错误:)...只需使用我的前叉。

您可以使用my fork of parslet检测循环的方式。 它捕获循环并告诉你发生了什么。 它比通常的parslet慢,所以切换回生产解析。

使用此Gemfile:

source "https://rubygems.org"

gem "parslet" , :git => "https://github.com/NigelThorne/parslet.git"
gem 'rspec'

你得到了这些结果:

 9:23:40.20 > bundle exec rspec parser.rb
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

Failures:

  1) RecurringGroupParser should parse a
     Failure/Error: is_expected.to parse "a"
     RuntimeError:
       Grammar contains an infinite loop applying 'NEWLINE{2, }' at char position 1
       ...a<-- here
     # ./parser.rb:33:in `block (2 levels) in <top (required)>'

  2) RecurringGroupParser should parse aa
     Failure/Error: is_expected.to parse "a\na"
     RuntimeError:
       Grammar contains an infinite loop applying 'NEWLINE{2, }' at char position 3
       ...a
       a<-- here
     # ./parser.rb:37:in `block (2 levels) in <top (required)>'

  3) RecurringGroupParser should parse aaa
     Failure/Error: is_expected.to parse "a\na\na"
     RuntimeError:
       Grammar contains an infinite loop applying 'NEWLINE{2, }' at char position 5
       ...a
       a
       a<-- here
     # ./parser.rb:41:in `block (2 levels) in <top (required)>'

  4) RecurringGroupParser should parse a a
     Failure/Error: is_expected.to parse "a\n\na"
       expected BLOCK to be able to parse "a\n\na"
     # ./parser.rb:45:in `block (2 levels) in <top (required)>'

  5) RecurringGroupParser should parse aa a
     Failure/Error: is_expected.to parse "a\na\n\na"
       expected BLOCK to be able to parse "a\na\n\na"
     # ./parser.rb:49:in `block (2 levels) in <top (required)>'

  6) RecurringGroupParser should parse aaa a
     Failure/Error: is_expected.to parse "a\naa\n\na"
       expected BLOCK to be able to parse "a\naa\n\na"
     # ./parser.rb:53:in `block (2 levels) in <top (required)>'

  7) RecurringGroupParser should parse a aa
     Failure/Error: is_expected.to parse "a\n\na\na"
       expected BLOCK to be able to parse "a\n\na\na"
     # ./parser.rb:57:in `block (2 levels) in <top (required)>'

  8) RecurringGroupParser should parse a aaa
     Failure/Error: is_expected.to parse "a\n\na\na\na"
       expected BLOCK to be able to parse "a\n\na\na\na"
     # ./parser.rb:61:in `block (2 levels) in <top (required)>'

  9) RecurringGroupParser should parse aa a
     Failure/Error: is_expected.to parse "a\na\n\na"
       expected BLOCK to be able to parse "a\na\n\na"
     # ./parser.rb:65:in `block (2 levels) in <top (required)>'

  10) RecurringGroupParser should parse aa aa
     Failure/Error: is_expected.to parse "a\na\n\na\na"
       expected BLOCK to be able to parse "a\na\n\na\na"
     # ./parser.rb:69:in `block (2 levels) in <top (required)>'

  11) RecurringGroupParser should parse aa aaa
     Failure/Error: is_expected.to parse "a\na\n\na\na\na"
       expected BLOCK to be able to parse "a\na\n\na\na\na"
     # ./parser.rb:73:in `block (2 levels) in <top (required)>'

  12) RecurringGroupParser should parse aaa aa
     Failure/Error: is_expected.to parse "a\naa\n\na\na"
       expected BLOCK to be able to parse "a\naa\n\na\na"
     # ./parser.rb:77:in `block (2 levels) in <top (required)>'

  13) RecurringGroupParser should parse aaa aaa
     Failure/Error: is_expected.to parse "a\naa\n\na\na\na"
       expected BLOCK to be able to parse "a\naa\n\na\na\na"
     # ./parser.rb:81:in `block (2 levels) in <top (required)>'

  14) RecurringGroupParser should parse a a a
     Failure/Error: is_expected.to parse "a\n\na\n\na"
       expected BLOCK to be able to parse "a\n\na\n\na"
     # ./parser.rb:85:in `block (2 levels) in <top (required)>'

  15) RecurringGroupParser should parse aa a a
     Failure/Error: is_expected.to parse "a\na\n\na\n\na"
       expected BLOCK to be able to parse "a\na\n\na\n\na"
     # ./parser.rb:89:in `block (2 levels) in <top (required)>'

  16) RecurringGroupParser should parse aaa a a
     Failure/Error: is_expected.to parse "a\naa\n\na\n\na"
       expected BLOCK to be able to parse "a\naa\n\na\n\na"
     # ./parser.rb:93:in `block (2 levels) in <top (required)>'

  17) RecurringGroupParser should parse a aa a
     Failure/Error: is_expected.to parse "a\n\na\na\n\na"
       expected BLOCK to be able to parse "a\n\na\na\n\na"
     # ./parser.rb:97:in `block (2 levels) in <top (required)>'

  18) RecurringGroupParser should parse aa aa a
     Failure/Error: is_expected.to parse "a\na\n\na\na\n\na"
       expected BLOCK to be able to parse "a\na\n\na\na\n\na"
     # ./parser.rb:101:in `block (2 levels) in <top (required)>'

  19) RecurringGroupParser should parse aaa aa a
     Failure/Error: is_expected.to parse "a\naa\n\na\na\n\na"
       expected BLOCK to be able to parse "a\naa\n\na\na\n\na"
     # ./parser.rb:105:in `block (2 levels) in <top (required)>'

  20) RecurringGroupParser should parse a aaa a
     Failure/Error: is_expected.to parse "a\n\na\naa\n\na"
       expected BLOCK to be able to parse "a\n\na\naa\n\na"
     # ./parser.rb:109:in `block (2 levels) in <top (required)>'

  21) RecurringGroupParser should parse aa aaa a
     Failure/Error: is_expected.to parse "a\na\n\na\naa\n\na"
       expected BLOCK to be able to parse "a\na\n\na\naa\n\na"
     # ./parser.rb:113:in `block (2 levels) in <top (required)>'

  22) RecurringGroupParser should parse aaa aaa a
     Failure/Error: is_expected.to parse "a\naa\n\na\naa\n\na"
       expected BLOCK to be able to parse "a\naa\n\na\naa\n\na"
     # ./parser.rb:117:in `block (2 levels) in <top (required)>'

  23) RecurringGroupParser should parse a a aa
     Failure/Error: is_expected.to parse "a\n\na\n\na\na"
       expected BLOCK to be able to parse "a\n\na\n\na\na"
     # ./parser.rb:121:in `block (2 levels) in <top (required)>'

  24) RecurringGroupParser should parse aa a aa
     Failure/Error: is_expected.to parse "a\na\n\na\n\na\na"
       expected BLOCK to be able to parse "a\na\n\na\n\na\na"
     # ./parser.rb:125:in `block (2 levels) in <top (required)>'

  25) RecurringGroupParser should parse aaa a aa
     Failure/Error: is_expected.to parse "a\naa\n\na\n\na\na"
       expected BLOCK to be able to parse "a\naa\n\na\n\na\na"
     # ./parser.rb:129:in `block (2 levels) in <top (required)>'

  26) RecurringGroupParser should parse a aa aa
     Failure/Error: is_expected.to parse "a\n\na\na\n\na\na"
       expected BLOCK to be able to parse "a\n\na\na\n\na\na"
     # ./parser.rb:133:in `block (2 levels) in <top (required)>'

  27) RecurringGroupParser should parse aa aa aa
     Failure/Error: is_expected.to parse "a\na\n\na\na\n\na\na"
       expected BLOCK to be able to parse "a\na\n\na\na\n\na\na"
     # ./parser.rb:137:in `block (2 levels) in <top (required)>'

  28) RecurringGroupParser should parse aaa aa aa
     Failure/Error: is_expected.to parse "a\naa\n\na\na\n\na\na"
       expected BLOCK to be able to parse "a\naa\n\na\na\n\na\na"
     # ./parser.rb:141:in `block (2 levels) in <top (required)>'

  29) RecurringGroupParser should parse a aaa aa
     Failure/Error: is_expected.to parse "a\n\na\naa\n\na\na"
       expected BLOCK to be able to parse "a\n\na\naa\n\na\na"
     # ./parser.rb:145:in `block (2 levels) in <top (required)>'

  30) RecurringGroupParser should parse aa aaa aa
     Failure/Error: is_expected.to parse "a\na\n\na\naa\n\na\na"
       expected BLOCK to be able to parse "a\na\n\na\naa\n\na\na"
     # ./parser.rb:149:in `block (2 levels) in <top (required)>'

  31) RecurringGroupParser should parse aaa aaa aa
     Failure/Error: is_expected.to parse "a\naa\n\na\naa\n\na\na"
       expected BLOCK to be able to parse "a\naa\n\na\naa\n\na\na"
     # ./parser.rb:153:in `block (2 levels) in <top (required)>'

  32) RecurringGroupParser should parse a a aaa
     Failure/Error: is_expected.to parse "a\n\na\n\na\na\na"
       expected BLOCK to be able to parse "a\n\na\n\na\na\na"
     # ./parser.rb:157:in `block (2 levels) in <top (required)>'

  33) RecurringGroupParser should parse aa a aaa
     Failure/Error: is_expected.to parse "a\na\n\na\n\na\na\na"
       expected BLOCK to be able to parse "a\na\n\na\n\na\na\na"
     # ./parser.rb:161:in `block (2 levels) in <top (required)>'

  34) RecurringGroupParser should parse aaa a aaa
     Failure/Error: is_expected.to parse "a\naa\n\na\n\na\na\na"
       expected BLOCK to be able to parse "a\naa\n\na\n\na\na\na"
     # ./parser.rb:165:in `block (2 levels) in <top (required)>'

  35) RecurringGroupParser should parse a aa aaa
     Failure/Error: is_expected.to parse "a\n\na\na\n\na\na\na"
       expected BLOCK to be able to parse "a\n\na\na\n\na\na\na"
     # ./parser.rb:169:in `block (2 levels) in <top (required)>'

  36) RecurringGroupParser should parse aa aa aaa
     Failure/Error: is_expected.to parse "a\na\n\na\na\n\na\na\na"
       expected BLOCK to be able to parse "a\na\n\na\na\n\na\na\na"
     # ./parser.rb:173:in `block (2 levels) in <top (required)>'

  37) RecurringGroupParser should parse aaa aa aaa
     Failure/Error: is_expected.to parse "a\naa\n\na\na\n\na\na\na"
       expected BLOCK to be able to parse "a\naa\n\na\na\n\na\na\na"
     # ./parser.rb:177:in `block (2 levels) in <top (required)>'

  38) RecurringGroupParser should parse a aaa aaa
     Failure/Error: is_expected.to parse "a\n\na\naa\n\na\na\na"
       expected BLOCK to be able to parse "a\n\na\naa\n\na\na\na"
     # ./parser.rb:181:in `block (2 levels) in <top (required)>'

  39) RecurringGroupParser should parse aa aaa aaa
     Failure/Error: is_expected.to parse "a\na\n\na\naa\n\na\na\na"
       expected BLOCK to be able to parse "a\na\n\na\naa\n\na\na\na"
     # ./parser.rb:185:in `block (2 levels) in <top (required)>'

  40) RecurringGroupParser should parse aaa aaa aaa
     Failure/Error: is_expected.to parse "a\naa\n\na\naa\n\na\na\na"
       expected BLOCK to be able to parse "a\naa\n\na\naa\n\na\na\na"
     # ./parser.rb:189:in `block (2 levels) in <top (required)>'

Finished in 0.01702 seconds (files took 0.26725 seconds to load)
40 examples, 40 failures    

请参阅使用Parslet解析缩进的this question