1

我只是从 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。

谢谢你的帮助!

4

1 回答 1

3

TL;博士; 如果您关心“^”之前的内容,则应首先对其进行解析。

---更长的答案---

解析器将始终使用所有文本。如果它不能消费所有东西,那么文档没有被语法完全描述。不要将其视为对您的文本执行“拆分”的东西……而是将其视为消耗文本流的智能状态机。

所以...由于您的完整语法需要消耗所有文档...在开发解析器时,您无法解析某些部分并留下其余部分。您希望它将您的文档转换为树,以便您可以将其操作为最终的来源。

如果你真的只想在分隔符之前使用所有文本,那么你可以做这样的事情......

假设我要解析一个 '^' 分隔的事物列表。

我可以有以下规则

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。当我这样做时,我将不得不放弃我的“所有不是'^'的东西”规则。

于 2014-04-18T07:16:41.733 回答