我一直有问题让scala组合器解析器(特别是通过JavaTokenParsers的RegexParsers)在int和float之间进行判断。我必须在这里遗漏一些非常基本的东西,因为我似乎无法在任何地方找到任何提及这一特定问题的东西。我已经包含了一个有问题的解析器代码的规范(当然,减去包括)。
@RunWith(classOf[JUnitRunner])
class SandboxSpec extends FlatSpec with ShouldMatchersForJUnit {
sealed trait PropertyValue
case class IntValue(value: Int) extends PropertyValue
case class RealValue(value: Float) extends PropertyValue
class Parser extends JavaTokenParsers {
def propertyLiteral : Parser[PropertyValue] = intValue | realValue
def realValue = floatingPointNumber ^^ {
s => RealValue(s.toFloat)
}
def intValue = wholeNumber ^^ {
s => IntValue(s.toInt)
}
}
"A java token parser" should "parse a float" in {
val p = new Parser()
val result = p.parseAll(p.propertyLiteral, "5.4") match {
case p.Success(x, _) => x
case p.NoSuccess(msg, _) => fail(msg)
}
result should be(RealValue(5.4f))
}
}
此操作失败,并显示以下错误消息:
string matching regex `\z' expected but `.' found
有一个想法,基于这个thread,我在整个数字之后放了<~ not(not('.'))
,但这似乎没有解决问题。
答案 0 :(得分:3)
你几乎就在那里 - 你唯一需要改变的是not(not('.'))
到not('.')
。为什么呢?
问题是intValue
总是消耗点之前的部分。如果您现在编写x ~ '.'
,则检查是否跟随点并将其与点之前的部分一起使用。但是你想在点不跟随时消费,因此你必须写x ~ not('.')
。
当你写x ~ not(not('.'))
时,你有一个双重否定,这与没有否定相同。这里唯一的区别是这样的双重否定允许您在不消耗它的情况下查找下一个输入。这是因为在失败时不会消耗输入以允许以下解析器再次解析它。如果出现双重故障,您既不会消耗任何东西,也会实现已经提到的查找。