我刚开始使用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^")
我试图用“礼物?”,
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。
谢谢你的帮助!
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
将匹配不结束或者用“^”开头的字符串。 然而,为了我需要拉出与该“为”关键字的值位是有用的
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} ]
我可能要忽略围绕“东西” S的white_space,我可能要所有单独处理6 +和4。 当我这样做,我将不得不扔掉我的规则“是不是‘^’所有的事情”。