如何使用 FastParse 精确匹配 'n' 个给定字符
How to match exactly 'n' given characters with FastParse
FastParse parser-combinator scala library gives you the .rep(n)
'Repeat' 方法允许您创建一个新的解析器,尝试解析给定的解析器 n
或更多 次。如果我想要 完全 n
匹配,那么规范的方法是什么?
在我的例子中,我想解析一个 40 个字符的 Git 提交 ID - 如果它超过 40 个字符,那不是提交 ID,它不应该匹配。
到目前为止我在文档中找到的最接近的示例是:
val unicodeEscape = P( "u" ~ hexDigit ~ hexDigit ~ hexDigit ~ hexDigit )
...通过简单重复匹配 4 个字符(对于 40 个字符的提交 ID 是冗长的)。
这些是解析器组合器,而不是正则表达式,答案类似于 \p{XDigit}{40}
.
啊,看起来它目前不可用,但它是已知的 'missing feature' FastParse:
好吧,即使这个功能现在不可用,您也可以编写一个应用 ~
给定次数的函数:
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
的运算符 *
(original implementation of 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 ...
}
自 issue was closed by this commit 起,rep 支持 max 关键字参数。它现在还支持 exactly 关键字参数。
hexdigit.rep(exactly = 40)
FastParse parser-combinator scala library gives you the .rep(n)
'Repeat' 方法允许您创建一个新的解析器,尝试解析给定的解析器 n
或更多 次。如果我想要 完全 n
匹配,那么规范的方法是什么?
在我的例子中,我想解析一个 40 个字符的 Git 提交 ID - 如果它超过 40 个字符,那不是提交 ID,它不应该匹配。
到目前为止我在文档中找到的最接近的示例是:
val unicodeEscape = P( "u" ~ hexDigit ~ hexDigit ~ hexDigit ~ hexDigit )
...通过简单重复匹配 4 个字符(对于 40 个字符的提交 ID 是冗长的)。
这些是解析器组合器,而不是正则表达式,答案类似于 \p{XDigit}{40}
.
啊,看起来它目前不可用,但它是已知的 'missing feature' FastParse:
好吧,即使这个功能现在不可用,您也可以编写一个应用 ~
给定次数的函数:
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
的运算符 *
(original implementation of 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 ...
}
自 issue was closed by this commit 起,rep 支持 max 关键字参数。它现在还支持 exactly 关键字参数。
hexdigit.rep(exactly = 40)