1

可能有人帮助我理解以下行为: parseAll (parseIf, "If bla blablaa")应该导致is expected. 相反,我总是得到string matching regex 'is\b' expected but 'b' found. 我想这与空格有关,因为" If bla is blablaa"(注意开头的空格)会导致相同的行为。我用 StandardTokenParsers 试了一下,一切正常。但不幸的是,STP 不支持正则表达式。后续问题:我将如何更改 RegexParsers 以便它使用字符串序列而不是字符序列?这将使错误报告变得更加容易。

lazy val parseIf = roleGiverIf ~ giverRole

lazy val roleGiverIf =
  kwIf ~> identifier | failure("""A rule must begin with if""")
lazy val giverRole =
  kwIs ~> identifier | failure("""is expected""")

lazy val keyword =
  kwIf | kwAnd | kwThen | kwOf | kwIs | kwFrom | kwTo

lazy val identifier =
  not(keyword) ~ roleEntityLiteral
// ...

def roleEntityLiteral: Parser[String] =
  """([^"\p{Cntrl}\\]|\\[\\/bfnrt]|\\u[a-fA-F0-9]{4})\S*""".r 
def kwIf: Parser[String] = "If\\b".r
def kwIs: Parser[String] = "is\\b".r

// ...

parseAll(parseIf, "If bla blablaa") match {
  case Success(parseIf, _) => println(parseIf)
  case Failure(msg, _) => println("Failure: " + msg)
  case Error(msg, _) => println("Error: " + msg)
4

1 回答 1

0

这个问题很奇怪。当你跟注|并且双方都失败时,选择最后发生失败的一方,并列偏向左侧的一方。

当您尝试使用 直接解析时giverRole,它会产生您期望的结果。但是,如果您在失败之前添加一个成功的匹配,它会产生您所看到的结果。

log原因相当微妙——我只是通过在所有解析器上添加语句才发现的。要理解它,您必须了解如何RegexParser跳过空格。具体来说,空格会被跳过accept因为failure不调用accept,所以不会跳过空格。

而失败kwIs发生在 上b,因为跳过了空格,失败failure发生在之后的空格上If。这里:

If bla blablaa
   ^ kwIs fails here
  ^ failure fails here

因此,上面的错误消息kwIs优先于我提到​​的规则。

您可以通过使解析器跳过空格而不匹配任何内容来解决此问题。此模式始终匹配很重要,否则您将收到更令人困惑的错误消息。这是我认为可行的建议:

"\\b|$".r ~ failure("is expected")

另一种解决方案是使用acceptIfacceptMatch不使用隐式正则表达式接受,在这种情况下,您可以提供量身定制的错误消息。

于 2011-11-12T20:15:47.427 回答