对于以下Parslet Parser
require 'parslet'
require 'parslet/convenience'
class Lines < Parslet::Parser
rule(:open_tag) {str('[')}
rule(:close_tag) {str(']')}
rule(:data) {str('name') | str('name_id') }
rule(:text) { open_tag >> data >> close_tag }
root :text
end
begin
p Lines.new.parse("[name_id]") <---- It throws error
rescue Parslet::ParseFailed => failure
Lines.new.parse_with_debug("[name_id]")
end
它出现以下错误
Failed to match sequence (OPEN_TAG NAME CLOSE_TAG) at line 1 char 6.
`- Expected "]", but got "_" at line 1 char 6.
如果我从
更改data rule
rule(:data) {str('name') | str('name_id') }
到
rule(:data) {str('name_id') | str('name') }
然后按预期工作。
但是,我正在根据用户输入动态生成规则。所以这个解决方案对我不起作用。
提前致谢。
答案 0 :(得分:2)
正在构建规则:data
,然后按照提供项目的顺序进行检查。要在较短的匹配器之前执行更长的匹配器,可以简单地对它们进行排序:
data = %w|name name_id|
data = data.sort { |a, b| b <=> a }
rule(:data) { data.map(&method(:str)).reduce(:|) }
答案 1 :(得分:1)
正如mudasobwa所说...名称将匹配,因此它没有机会尝试使用name_id。 您需要更改订单,以便首先尝试使用name_id,或者您需要使名称无法匹配。你如何做到这一点取决于你的语法。
require 'parslet'
require 'parslet/convenience'
class Lines < Parslet::Parser
rule(:open_tag) {str('[')}
rule(:close_tag) {str(']')}
rule(:data) { str('name]') | str('name_id]') } # <-- you can't let a matcher match unless it really is a match, so here it works because name] fails for name_id
rule(:text) { open_tag >> data }
root :text
end
begin
p Lines.new.parse("[name_id]")
rescue Parslet::ParseFailed => failure
Lines.new.parse_with_debug("[name_id]")
end
我想我会让解析器为我打破文本,然后检查结构......例如
require 'parslet'
require 'parslet/convenience'
class Lines < Parslet::Parser
rule(:open_tag) {str('[')}
rule(:close_tag) {str(']')}
rule(:data) { (close_tag.absnt? >> any).repeat(1).as(:data) }
rule(:text) { open_tag >> data >> close_tag }
root :text
end
begin
p Lines.new.parse("[name_id]") # => {:data=>"name_id"@1}
rescue Parslet::ParseFailed => failure
Lines.new.parse_with_debug("[name_id]")
end
Parslet旨在分两个阶段工作..第一阶段将您的doc转换为树。第二个将您的树转换为您想要的数据表示。
在这种情况下,第一个解析拉出结构。秒传递可以检查“name_id”是否有效。等。