首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Parboiled2:如何处理依赖域?

Parboiled2:如何处理依赖域?
EN

Stack Overflow用户
提问于 2018-02-21 02:06:20
回答 2查看 136关注 0票数 1

我试图使用优秀的parboiled2库解析文件格式,其中某些字段的存在取决于已处理的一个或多个字段的值。

例如,假设我有两个字段,第一个字段是指示第二个字段是否存在的标志。也就是说,如果第一个字段是true,那么第二个字段(在本例中是一个整数值)是存在的,必须进行处理--但是如果它是false,那么第二个字段根本不存在。注意,第二个字段不是可选的-它要么必须被处理(如果第一个字段是true),要么不能被处理(如果第一个字段是false)。

因此,如果第三个字段(我们假设它总是存在)是一个引号字符串,那么以下两行都是有效的:

代码语言:javascript
复制
true 52 "Some quoted string"
false "Some other quoted string"

但这将是无效的:

代码语言:javascript
复制
false 25 "Yet another quoted string"

忽略第三个字段,如何编写规则来解析前两个字段?(从文档中我看不出来,谷歌搜索到目前为止也没有帮助.)

UPDATE:我应该澄清,我不能使用如下规则,因为我解析的格式实际上比我的示例要复杂得多:

代码语言:javascript
复制
import org.parboiled2._

class MyParser(override val input: ParserInput)
extends Parser {

  def ws = // whitepsace rule, puts nothing on the stack.

  def intField = // parse integer field, pushes Int onto stack...

  def dependentFields = rule {
    ("true" ~ ws ~ intField) | "false" ~> //etc.
  }
}

更新2:我修改了以下内容以使我的意图更加清晰:

我要寻找的是一个有效的等价规则,该规则仅在满足条件时执行匹配:

代码语言:javascript
复制
import org.parboiled2._

class MyParser(input: ParserInput)
extends Parser {

  def ws = // whitepsace rule, puts nothing on the stack.

  def intField = // parse integer field, pushes Int onto stack...

  def boolField = // parse boolean field, pushes Boolean onto stack...

  def dependentFields = rule {
    boolField ~> {b =>

      // Match "ws ~ intField" only if b is true. If match succeeds, push Some(Int); if match
      // fails, the rule fails. If b is false, pushes None without attempting the match.
      conditional(b, ws ~ intField)
    }
  }
}

也就是说,只有在ws ~ intField结果为true值的情况下,才匹配true。这样的事有可能吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-02-21 12:31:13

是的,您可以在test解析器操作的帮助下实现这样的函数:

代码语言:javascript
复制
def conditional[U](bool: Boolean, parse: () => Rule1[U]): Rule1[Option[U]] = rule {
  test(bool) ~ parse() ~> (Some(_)) | push(None)
}

根据文档的元规则部分,它只能通过传递函数来生成规则来工作。您必须按照以下方式定义dependentFields规则:

代码语言:javascript
复制
def dependentFields = rule {
  boolField ~> (conditional(_, () => rule { ws ~ intField }))
}

更新:

虽然test(pred) ~ opt1 | opt2是一种常见的技术,但它确实会回溯并尝试应用opt2,如果test成功的话-- test,但opt1失败。以下是防止这种回溯的两种可能的解决办法。

您可以使用~!~规则组合器,它具有“剪切”语义并禁止对其本身进行回溯:

代码语言:javascript
复制
def conditional2[U](bool: Boolean, parse: () => Rule1[U]): Rule1[Option[U]] = rule {
  test(bool) ~!~ parse() ~> (Some(_)) | push(None)
}

或者您实际上在规则之外使用if来检查布尔参数并返回两个可能的规则之一:

代码语言:javascript
复制
def conditional3[U](bool: Boolean, parse: () => Rule1[U]): Rule1[Option[U]] =
  if (bool) rule { parse() ~> (Some(_: U)) } 
  else rule { push(None) }
票数 2
EN

Stack Overflow用户

发布于 2018-02-21 03:10:19

我会这样做:

代码语言:javascript
复制
extends Parser {

  def dependentFields: Rule1[(Boolean, Option[Int], String)] = rule {
     ("true" ~ ws ~ trueBranch | "false" ~ ws ~ falseBranch)
  }

  def trueBranch = rule {
     intField ~ ws ~ stringField ~> { (i, s) => (true, Some(i), s) }
  }

  def falseBranch = rule {
     stringField ~> { s => (false, None, s) }
  }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48897117

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档