我刚开始使用ruby和parslet,所以这对其他人来说可能是显而易见的(希望如此)。
我想要将所有单词提取到分隔符(^)而不消耗它
以下规则适用(但使用分隔符),结果为{:wrd=>"otherthings"@0, :delim=>"^"@11}
require 'parslet'
class Mini < Parslet::Parser
rule(:word) { match('[a-zA-Z]').repeat}
rule(:delimeter) { str('^') }
rule(:othercontent) { word.as(:wrd) >> delimeter.as(:delim) }
root(:othercontent)
end
puts Mini.new.parse("otherthings^")
我试图使用&#39; present?&#39;,
require 'parslet'
class Mini < Parslet::Parser
rule(:word) { match('[a-zA-Z]').repeat}
rule(:delimeter) { str('^') }
rule(:othercontent) { word.as(:wrd) >> delimeter.present? }
root(:othercontent)
end
puts Mini.new.parse("otherthings^")
但这会引发异常:
Failed to match sequence (wrd:WORD &DELIMETER) at line 1 char 12. (Parslet::ParseFailed)
稍后我会想要检查分隔符右侧的单词以构建更复杂的语法,这就是我不想使用分隔符的原因。
我正在使用parslet 1.5.0。
感谢您的帮助!
答案 0 :(得分:3)
TL; DR; 如果你关心“^”之前的内容,你应该首先解析它。
---更长的答案---
解析器将始终使用所有文本。如果它不能消耗所有内容,那么语法就不能完整地描述文档。而不是将其视为在文本上“分裂”的东西......而是将其视为消耗文本流的聪明状态机。
所以...因为你的完整语法需要消耗所有文档...在开发你的解析器时,你不能让它解析一些部分而剩下的部分。您希望它将您的文档转换为树,以便您可以将其操作到最终。
如果你真的想在分隔符之前只使用所有文本,那么你可以做这样的事情......
说我打算解析'^'分开的事情列表。
我可以遵守以下规则
rule(:thing) { (str("^").absent? >> any).repeat(1) } # anything that's not a ^
rule(:list) { thing >> ( str("^") >> thing).repeat(0) } #^ separated list of things
这将如下工作
parse("thing1^thing2") #=> "thing1^thing2"
parse("thing1") #=> "thing1"
parse("thing1^") #=> ERROR ... nothing after the ^ there should be a 'thing'
这意味着list
将匹配未结束或以'^'开头的字符串。为了有用,我需要使用“as”关键字
rule(:thing) { (str("^").absent? >> any).repeat(1).as(:thing) }
rule(:list) { thing >> ( str("^") >> thing).repeat(0) }
现在当list
匹配一个字符串时,我得到了一系列“事物”的哈希值。
parse("thing1^thing2") #=> [ {:thing=>"thing1"@0} , {:thing=>"thing2"@7} ]
实际上,你可能会关心“事物”是什么......不只是有什么东西会去那里。
在这种情况下......你应该首先定义这些规则...因为你不想使用解析器拆分“^”然后重新解析字符串以计算出它们的构成。
例如:
parse("6 + 4 ^ 2")
# => [ {:thing=>"6 + 4 "@0}, {:thing=>" 2"@7} ]
我可能想忽略“事物”周围的white_space,我可能想分别处理6 +和4。当我这样做时,我将不得不扔掉我所有“不是'^'”的规则。