我有以下规格
it "parses a document with only an expression" do
puts parser.document.should parse("[b]Hello World[/b]")
end
it "parses a document with only text" do
puts parser.document.should parse(" Hello World")
end
it "parses a document with both an expression and text" do
puts parser.document.should parse("[b]Hello World[/b] Yes hello")
end
对于以下Parslet Parser
class Parser < Parslet::Parser
rule(:open_tag) do
parslet = str('[')
parslet = parslet >> (str(']').absent? >> match("[a-zA-Z]")).repeat(1).as(:open_tag_name)
parslet = parslet >> str(']')
parslet
end
rule(:close_tag) do
parslet = str('[/')
parslet = parslet >> (str(']').absent? >> match("[a-zA-Z]")).repeat(1).as(:close_tag_name)
parslet = parslet >> str(']')
parslet
end
rule(:text) { any.repeat(1).as(:text) }
rule(:expression) do
# [b]Hello World[/b]
# open tag, any text up until closing tag, closing tag
open_tag.present?
close_tag.present?
parslet = open_tag >> match("[a-zA-Z\s?]").repeat(1).as(:enclosed_text) >> close_tag
parslet
end
rule(:document) do
expression | text
end
前两个测试通过就好了,我可以通过put
将它们看到命令行,原子的类型正确。但是,当我尝试使用表达式和纯文本解析文档时,它无法解析纯文本,失败并出现以下错误
Parslet::UnconsumedInput: Don't know what to do with " Yes hello" at line 1 char 19.
我认为我遗漏了一些关于定义:文档规则的内容。我想要的是会消耗任意数量的序列表达式和纯文本,而我所拥有的规则将消耗每个原子个体,在同一个字符串中使用它们会导致失败。
答案 0 :(得分:4)
你要找的是这样......
require 'parslet'
class ExampleParser < Parslet::Parser
rule(:open_tag) do
str('[') >>
match["a-zA-Z"].repeat(1).as(:open_tag_name) >>
str(']')
end
open_tag规则不需要排除']'字符,因为匹配只允许使用字母。
rule(:close_tag) do
str('[/') >>
match["a-zA-Z"].repeat(1).as(:close_tag_name) >>
str(']')
end
同样在这里
rule(:text) do
(open_tag.absent? >>
close_tag.absent? >>
any).repeat(1).as(:text)
end
如果你在这里排除了打开和关闭标签..你知道你只处理文本。 注意:一旦你排除了你不想要的东西,我喜欢这种使用“any”的技巧,但是如果你以后要重构,因为你的排除列表可能需要增长,所以请记住这一点。 注2:您可以进一步简化这一点,如下所示..
rule(:text) do
(str('[').absent? >> any).repeat(1).as(:text)
end
..如果您根本不想在文本中使用任何方括号。
rule(:expression) do
# [b]Hello World[/b]
open_tag >> text.as(:enclosed_text) >> close_tag
end
这变得更加简单,因为文本不能包含close_tag
rule(:document) do
(expression | text).repeat
end
我在重复中添加了你错过了(正如亚光所指出的)
end
require 'rspec'
require 'parslet/rig/rspec'
describe 'example' do
let(:parser) { ExampleParser.new }
context 'document' do
it "parses a document with only an expression" do
parser.document.should parse("[b]Hello World[/b]")
end
it "parses a document with only text" do
parser.document.should parse(" Hello World")
end
it "parses a document with both an expression and text" do
parser.document.should parse("[b]Hello World[/b] Yes hello")
end
end
end
RSpec::Core::Runner.run([])
希望这能为您提供有关使用Parslet的一些提示。 :)
答案 1 :(得分:2)
对于您要document
使用的rule(:document) do
(expression | text).repeat
end
规则:
text
您还需要更改[
规则;目前,如果它开始匹配,它将消耗包括应该开始新expression
的任何rule(:text) { match['^\['].repeat(1).as(:text) }
的所有内容。这样的事情应该有效:
{{1}}