我正在尝试使用用 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
)带空格,例如: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
组成,并且不缩进,但以后可以轻松更改,并且与无法完成解析无关。我也很确定 rule :blank_line
中的 chunk.absent?
和 rule 中的
但我不知道如何解决这个问题并提供打破递归的标准。需要任何帮助!any.absent?
之间存在冲突:newline
最佳答案
在这种情况下,换行符可以是 eof。在这种情况下换行。 Repeat(2) 重复匹配 eof。你想要“重复(2,2)”。你可以让这些错误很容易被发现:)...只需使用我的 fork 。
您可以使用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
参见this question关于用 Parslet 解析缩进。
关于ruby - 解析markdown缩进代码块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30485292/