Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala Parboiled2:如何处理依赖字段?_Scala_Parboiled2 - Fatal编程技术网

Scala Parboiled2:如何处理依赖字段?

Scala Parboiled2:如何处理依赖字段?,scala,parboiled2,Scala,Parboiled2,我试图使用优秀的库解析一种文件格式,其中某些字段的存在取决于一个或多个已处理字段的值 例如,假设我有两个字段,第一个字段是指示第二个字段是否存在的标志。也就是说,如果第一个字段为true,则第二个字段(在本例中为整数值)存在并且必须进行处理-但是如果它为false,则第二个字段根本不存在。请注意,第二个字段不是可选的-必须对其进行处理(如果第一个字段为true),或者不进行处理(如果第一个字段为false) 因此,如果第三个字段(我们假设它始终存在)是带引号的字符串,则以下两行都有效: true

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

例如,假设我有两个字段,第一个字段是指示第二个字段是否存在的标志。也就是说,如果第一个字段为
true
,则第二个字段(在本例中为整数值)存在并且必须进行处理-但是如果它为
false
,则第二个字段根本不存在。请注意,第二个字段不是可选的-必须对其进行处理(如果第一个字段为
true
),或者不进行处理(如果第一个字段为
false

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

true 52 "Some quoted string"
false "Some other quoted string"
但这是无效的:

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

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

更新2:我修改了以下内容,以使我的意图更加明确:

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


也就是说,
ws~intField
仅在
boolField
产生
true
值时匹配。这样做可能吗?

我会这样做:

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) }
  }
}

是的,您可以借助
test
解析器操作来实现这样的功能:

def conditional[U](bool: Boolean, parse: () => Rule1[U]): Rule1[Option[U]] = rule {
  test(bool) ~ parse() ~> (Some(_)) | push(None)
}
根据文档的说明,它只能通过传递函数来生成规则。您必须定义
dependentFields
规则如下:

def dependentFields = rule {
  boolField ~> (conditional(_, () => rule { ws ~ intField }))
}

更新:

虽然
test(pred)~opt1 | opt2
是一种常见的技术,但如果
test
成功
test
,但
opt1
失败,它会回溯并尝试应用
opt2
。这里有两种可能的解决方案来防止这种回溯

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

def conditional2[U](bool: Boolean, parse: () => Rule1[U]): Rule1[Option[U]] = rule {
  test(bool) ~!~ parse() ~> (Some(_)) | push(None)
}
或者在规则之外实际使用
if
检查布尔参数并返回两个可能的规则之一:

def conditional3[U](bool: Boolean, parse: () => Rule1[U]): Rule1[Option[U]] =
  if (bool) rule { parse() ~> (Some(_: U)) } 
  else rule { push(None) }

@MikeAllen如果您的逻辑仍然在布尔值上分支,我会说我的方法(和您最初的方法)是有效的。否则,我对您的数据结构没有足够的输入,无法对如何解析它做出有效的假设。碰巧,我不是在布尔值上分支。在我的实际案例中,更准确的说法是,第一个字段实际上是一个包含10个标志的位字段,每个标志确定是否存在其他数据-距离位字段一定距离(即不紧跟其后)。所以我想表达的是,只有当某个表达式为真时,才需要解析字段。这能澄清我的问题吗?谢谢!这(几乎)行得通!我知道元规则需要函数(文档对此很清楚)。我想我没有意识到,如果
测试
操作失败,我可以使用|子句推送一个值。太好了!不幸的是,如果解析操作本身失败,该子句也将执行——因此我无法区分错误的测试条件和解析
ws~intField
规则的失败。有什么建议吗?再说一次,当我测试它时,它似乎确实做了需要做的事情。你能详细说明一下它是如何工作的吗?特别是,我有点困惑,如果解析规则(
ws~intField
,在本例中)不匹配,|子句如何不执行?谢谢你的帮助@米凯伦:我可以在你的评论中重复这个问题。可能是因为在
dependentFields
规则之后匹配了
EOI
或其他不兼容的内容,导致解析器失败。我现在用两种可能的解决方案更新了答案。谢谢你的更新-太棒了!我必须检查我的测试代码中发生了什么,但我期待您描述的行为。使用
~~适合我。我不确定在一个函数中包含多个
规则
s是否合法(比如,
if…else
表达式),但知道这一点也很好。再次感谢!嗯,我得到了正确的答案,但似乎是因为错误的原因。使用
~
~,两者之间没有区别~
测试
条件之后。我有两个版本的分支(
master
带切口的分支,
nocut
不带切口的分支)。如果有时间,如果你能检查一下结果,看看我可能做错了什么,我将非常感激。谢谢
def conditional2[U](bool: Boolean, parse: () => Rule1[U]): Rule1[Option[U]] = rule {
  test(bool) ~!~ parse() ~> (Some(_)) | push(None)
}
def conditional3[U](bool: Boolean, parse: () => Rule1[U]): Rule1[Option[U]] =
  if (bool) rule { parse() ~> (Some(_: U)) } 
  else rule { push(None) }