使用Scala的解析器组合器时,如何忽略不匹配的前一文本?

时间:2012-04-03 08:57:47

标签: scala parser-combinators

我真的很喜欢解析器组合器,但是当我不关心相关文本之前的文本时,我对提出数据的解决方案不满意。

考虑这个小解析器来获取金额:

import scala.util.parsing.combinator._

case class Amount(number: Double, currency: String)

object MyParser extends JavaTokenParsers {
  def number = floatingPointNumber ^^ (_.toDouble)
  def currency = """\w+""".r ^? ({
    case "USD" => "USD"
    case "EUR" => "EUR"
  }, "Unknown currency code: " + _)

  def amount = (number ~ currency) ^^ {
    case num ~ curr => Amount(num, curr)
  } | currency ~ number ^^ {
    case curr ~ num => Amount(num, curr)
  }

  def junk = """\S+""".r
  def amountNested: Parser[Any] = amount | junk ~> amountNested
}

正如您所看到的,如果我给解析器一个以有效数据开头的字符串,我可以轻松地返回Amount

scala> MyParser.parse(MyParser.amount, "101.41 EUR")
res7: MyParser.ParseResult[Amount] = [1.11] parsed: Amount(101.41,EUR)

scala> MyParser.parse(MyParser.amount, "EUR 102.13")
res8: MyParser.ParseResult[Amount] = [1.11] parsed: Amount(102.13,EUR)

但是,当它之前存在不匹配的文本时,它会失败:

scala> MyParser.parse(MyParser.amount, "I have 101.41 EUR")
res9: MyParser.ParseResult[Amount] = 
[1.2] failure: Unknown currency code: I

I have 101.41 EUR
 ^

我的解决方案是amountNested解析器,在其中递归尝试查找Amount。这有效,但它提供ParseResult[Any]

scala> MyParser.parse(MyParser.amountNested, "I have 101.41 EUR")
res10: MyParser.ParseResult[Any] = [1.18] parsed: Amount(101.41,EUR)

遗憾的是,这种类型信息的丢失(当然可以使用模式匹配“检索”),因为任何成功都会包含Amount

有没有办法继续搜索我的输入("I have 101.41 EUR"),直到我有匹配但没有Parser[Any]

查看ScalaDocs似乎*上的Parser方法可能会有所帮助,但是当我尝试以下内容时,我得到的只是失败或无限循环:

def amount2 = ("""\S+""".r *) ~> amount

1 个答案:

答案 0 :(得分:1)

如果您声明您的amountNested为Parser [Amount],那么它可以很好地检查:

def amountNested: Parser[Amount] = amount | junk ~> amountNested