3

FastParse parser -combinator scala 库为您提供了.rep(n)“重复”方法,以允许您创建一个新的解析器,该解析器尝试解析 givenParsern 或更多次。如果我想要完全 n匹配,那么规范的方法是什么?

在我的例子中,我想解析一个 40 个字符的 Git 提交 id - 如果它超过 40 个字符,那不是一个提交 id,它不应该是匹配的。

到目前为止,我在文档中找到的最接近的示例是:

val unicodeEscape = P( "u" ~ hexDigit ~ hexDigit ~ hexDigit ~ hexDigit )

...与简单重复的 4 个字符匹配(对于 40 个字符的提交 ID 是冗长的)。

这些是解析器组合器,而不是正则表达式,答案类似于\p{XDigit}{40}.

4

3 回答 3

7

由于此提交关闭了问题,因此 rep 支持 max 关键字参数。它现在还支持完全关键字参数。

hexdigit.rep(exactly = 40)
于 2017-01-01T19:55:14.273 回答
4

好吧,即使这个功能现在不可用,您也可以编写一个应用~给定次数的函数:

def repExactly(parser: Parser[Unit])(times: Int): Parser[Unit] =
  Iterator.iterate(parser)(_ ~ parser).drop(times - 1).next()

这是一个小测试:

object Main extends App {

  import fastparse._

  def repExactly(parser: Parser[Unit])(times: Int): Parser[Unit] =
    Iterator.iterate(parser)(_ ~ parser).drop(times - 1).next()

  val hexDigit = P( CharIn('0'to'9', 'a'to'f', 'A'to'F') )
  def fiveHexDigits = repExactly(hexDigit)(5) ~ End

  println(fiveHexDigits.parse("123a"))
  println(fiveHexDigits.parse("123ab"))
  println(fiveHexDigits.parse("123abc"))

}

输出是

Failure(hexDigit:4 / CharIn("0123456789abcdefABCDEF"):4 ..."", false)
Success((), 5)
Failure(End:5 ..."c", false)

这是一个通用的方法来实现这个功能作为一个操作符*Parser最初的实现rep做了一些非常复杂的事情,所以我的实现可能无法解释某些情况。另外,我没有测试它如何与有削减的参数一起工作) :

object Main extends App {

  import fastparse._

  implicit class ParserExtension[T](parser: Parser[T]) {
    def *[R] (times: Int)(implicit ev: Implicits.Repeater[T, R]): Parser[R] = {
      assert(times >= 1)

      Iterator.iterate(parser map { t =>
        val acc = ev.initial
        ev.accumulate(t, acc)
        acc
      }){ prev: Parser[ev.Acc] =>
        (prev ~ parser) map {
          case (acc, t) =>
            ev.accumulate(t, acc)
            acc
        }
      }.drop(times - 1).next() map (acc => ev.result(acc))
    }
  }

  val hexDigit = P( CharIn('0'to'9', 'a'to'f', 'A'to'F') )

  val fiveDigitsSeq = (hexDigit.! * 5) ~ End

  println(fiveDigitsSeq.parse("123a"))   // Failure ...
  println(fiveDigitsSeq.parse("123ab"))  // Success(ArrayBuffer(1, 2, 3, a, b), 5)
  println(fiveDigitsSeq.parse("123abc")) // Failure ...
  println()

  val fiveDigitsStr = (hexDigit * 5).! ~ End

  println(fiveDigitsStr.parse("123a"))   // Failure ...
  println(fiveDigitsStr.parse("123ab"))  // Success(123ab, 5)
  println(fiveDigitsStr.parse("123abc")) // Failure ...
}
于 2015-06-13T13:27:21.970 回答
2

啊,看起来它目前不可用,但它是 FastParse 的一个已知“缺失功能”:

https://github.com/lihaoyi/fastparse/issues/27

于 2015-06-13T13:19:12.173 回答