RegexParsers的自定义错误

时间:2011-11-12 01:19:37

标签: parsing scala parser-combinators

有人可以帮我理解以下行为: 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)

1 个答案:

答案 0 :(得分:0)

这个问题很奇怪。当您致电|并且双方都失败时,会选择失败发生在最后的一侧,并选择偏向左侧的那一方。

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

原因相当微妙 - 我只是通过在所有解析器上撒上log语句来找到它。要理解它,您必须了解 RegexParser如何跳过空格。具体来说,在accept 上跳过空格。由于failure不会调用accept,因此不会跳过空格。

虽然kwIsb发生了失败,但由于空格被跳过,failure If空格发生 >。这里:

If bla blablaa
   ^ kwIs fails here
  ^ failure fails here

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

您可以通过使解析器跳过空格而不匹配任何内容来解决此问题。重要的是,此模式始终匹配,否则您将收到更加混乱的错误消息。以下是我认为有效的建议:

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

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