gpt4 book ai didi

regex - Scala RegexParsers 中的非贪婪匹配

转载 作者:行者123 更新时间:2023-12-03 22:31:57 25 4
gpt4 key购买 nike

假设我正在用 Scala 编写一个基本的 SQL 解析器。我有以下几点:

class Arith extends RegexParsers {
def selectstatement: Parser[Any] = selectclause ~ fromclause
def selectclause: Parser[Any] = "(?i)SELECT".r ~ tokens
def fromclause: Parser[Any] = "(?i)FROM".r ~ tokens
def tokens: Parser[Any] = rep(token) //how to make this non-greedy?
def token: Parser[Any] = "(\\s*)\\w+(\\s*)".r
}

尝试将 selectstatement 与 SELECT foo FROM bar 匹配时,我如何防止选择子句由于 rep(token) 而吞噬整个短语在 ~ tokens ?

换句话说,如何在 Scala 中指定非贪婪匹配?

为了澄清起见,我完全知道我可以在 String 模式本身中使用标准的非贪婪语法 (*?) 或 (+?),但我想知道是否有办法在 def 标记中的更高级别指定它。例如,如果我像这样定义了 token :
def token: Parser[Any] = stringliteral | numericliteral | columnname

那么如何为 def token 中的 rep(token) 指定非贪婪匹配?

最佳答案

不容易,因为不会重试成功的匹配。考虑,例如:

object X extends RegexParsers {
def p = ("a" | "aa" | "aaa" | "aaaa") ~ "ab"
}

scala> X.parseAll(X.p, "aaaab")
res1: X.ParseResult[X.~[String,String]] =
[1.2] failure: `ab' expected but `a' found

aaaab
^

第一次匹配成功,在括号内的解析器中,所以它进行到下一个。那个失败了,所以 p失败的。如 p是替代匹配的一部分,将尝试替代,所以诀窍是生产可以处理那种事情的东西。

假设我们有这个:
def nonGreedy[T](rep: => Parser[T], terminal: => Parser[T]) = Parser { in =>
def recurse(in: Input, elems: List[T]): ParseResult[List[T] ~ T] =
terminal(in) match {
case Success(x, rest) => Success(new ~(elems.reverse, x), rest)
case _ =>
rep(in) match {
case Success(x, rest) => recurse(rest, x :: elems)
case ns: NoSuccess => ns
}
}

recurse(in, Nil)
}

然后你可以像这样使用它:
def p = nonGreedy("a", "ab")

顺便说一句,我总是发现查看其他事物的定义方式有助于想出诸如 nonGreedy 之类的东西。以上。特别是看如何 rep1已定义,以及如何更改它以避免重新评估其重复参数——同样的事情可能对 nonGreedy 有用。 .

这是一个完整的解决方案,稍作更改以避免消耗“终端”。
trait NonGreedy extends Parsers {
def nonGreedy[T, U](rep: => Parser[T], terminal: => Parser[U]) = Parser { in =>
def recurse(in: Input, elems: List[T]): ParseResult[List[T]] =
terminal(in) match {
case _: Success[_] => Success(elems.reverse, in)
case _ =>
rep(in) match {
case Success(x, rest) => recurse(rest, x :: elems)
case ns: NoSuccess => ns
}
}

recurse(in, Nil)
}
}

class Arith extends RegexParsers with NonGreedy {
// Just to avoid recompiling the pattern each time
val select: Parser[String] = "(?i)SELECT".r
val from: Parser[String] = "(?i)FROM".r
val token: Parser[String] = "(\\s*)\\w+(\\s*)".r
val eof: Parser[String] = """\z""".r

def selectstatement: Parser[Any] = selectclause(from) ~ fromclause(eof)
def selectclause(terminal: Parser[Any]): Parser[Any] =
select ~ tokens(terminal)
def fromclause(terminal: Parser[Any]): Parser[Any] =
from ~ tokens(terminal)
def tokens(terminal: Parser[Any]): Parser[Any] =
nonGreedy(token, terminal)
}

关于regex - Scala RegexParsers 中的非贪婪匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7812610/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com