解析markdown缩进代码块

我试图使用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 )和空行( \n\n ),例如: a aaa aa

 # recurring_group_parser.rb require 'parslet' require 'rspec' require 'parslet/rig/rspec' class RecurringGroupParser > 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 aa' do is_expected.to parse "aa" 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 aaa' do is_expected.to parse "aaa" end it 'should parse aa aa' do is_expected.to parse "aa aa" end it 'should parse aaa aa' do is_expected.to parse "aaa aa" 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 aa aa' do is_expected.to parse "aa 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 aa aaa' do is_expected.to parse "aa 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 > 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 aa' 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 aaa' do is_expected.to parse "a\n\na\n\na" end it 'should parse aa aa' do is_expected.to parse "a\na\n\na\n\na" end it 'should parse aaa aa' 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 aa 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 aa 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?之间有冲突chunk.absent?rule :blank_lineany.absent?rule :newline但我不知道如何解决这个问题,并提供打破递归的标准。 任何想要的帮助!

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

您可以使用我的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 ' 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 ' 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 ' 4) RecurringGroupParser should parse aa 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 ' 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 ' 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 ' 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 ' 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 ' 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 ' 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 ' 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 ' 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 ' 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 ' 14) RecurringGroupParser should parse aaa 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 ' 15) RecurringGroupParser should parse aa aa 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 ' 16) RecurringGroupParser should parse aaa aa 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 ' 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 ' 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 ' 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 ' 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 ' 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 ' 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 ' 23) RecurringGroupParser should parse aa 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 ' 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 ' 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 ' 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 ' 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 ' 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 ' 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 ' 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 ' 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 ' 32) RecurringGroupParser should parse aa 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 ' 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 ' 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 ' 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 ' 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 ' 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 ' 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 ' 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 ' 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 ' Finished in 0.01702 seconds (files took 0.26725 seconds to load) 40 examples, 40 failures 

关于使用Parslet解析缩进的问题 。