Başarılı bir eşleşme yeniden denenmediği için kolay değil.
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
^
ilk maç parantez içindeki ayrıştırıcı, başarılı oldu, bu yüzden bir sonrakine devam: örneğin, düşünün. Bu başarısız oldu, bu yüzden p
başarısız oldu. p
alternatif eşleşmelerin bir parçası olsaydı, alternatif denenecek, bu yüzden hile bu tür şeyleri başarabilecek bir şey üretmek.
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)
}
Daha sonra, bu gibi kullanabilirsiniz:
Şimdi bu var diyelim
def p = nonGreedy("a", "ab")
arada, ben her zaman ne kadar başka şeyler tanımlanır bakarak yardımcı olduğunu bulduk Yukarıdaki nonGreedy
gibi şeyler ile gelmeye çalışıyor. Özellikle, rep1
'un nasıl tanımlandığına ve tekrarlama parametresini yeniden değerlendirmekten kaçınmak için nasıl değiştirildiğine bakın - aynı şey muhtemelen nonGreedy
'da yararlı olacaktır.
"Terminal" tüketimini önlemek için küçük bir değişiklikle birlikte tam bir çözüm. Biz (https://en.wikipedia.org/wiki/Parsing_expression_grammar#Operational_interpretation_of_parsing_expressions) burada [PEG özelliği ile] ilgileniyor gibi
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)
}
Öyle görünüyor: düzenli ifade matchers açgözlülükle eşleştirerek başlayın, ancak olabilir Oysa daha sonra backtrack olacak ve başarısız olursa CFG'ler her olasılığı denerse daha kısa maçlar deneyebilir, PEG'nin * *, '+' ve '' 'operatörleri her zaman hırslı davranır, mümkün olduğu kadar fazla girdi tüketir ve asla geri dönmezler: İfade' a * her zaman pek çok a, giriş dizesinde ardışık olarak kullanılabilir, bu da (a * a) 'nın her zaman başarısız olmasına neden olur. –