2012-10-31 13 views
5

Czy można odwrócić mecze z kombinatorami parsera Scala? Próbuję dopasować linie za pomocą analizatora składni, które nie mają wartości , a zaczynają od zestawu słów kluczowych. Mógłbym to zrobić z denerwującym negatywnym wyrażeniem regularnym o zerowej szerokości (na przykład "(?!h1|h2).*"), ale wolałbym zrobić to za pomocą parsera Scala. Najlepsze, co udało mi się wymyślić, to:Scala parser-combinators: jak odwrócić mecze?

def keyword = "h1." | "h2." 
def alwaysfails = "(?=a)b".r 
def linenotstartingwithkeyword = keyword ~! alwaysfails | ".*".r 

Pomysł jest tutaj, że używam ~! aby zabezpieczyć się przed powrotem do dopasowanego do regexp, a następnie kontynuować wyrażenie "(? = a) b" .r, które nie pasuje do niczego. (Nawiasem mówiąc, czy istnieje predefiniowany analizator składniowy, który zawsze kończy się niepowodzeniem?) W ten sposób linia nie zostanie dopasowana, jeśli zostanie znalezione słowo kluczowe, ale zostanie dopasowana, jeśli słowo kluczowe nie pasuje.

Zastanawiam się, czy istnieje lepszy sposób na zrobienie tego. Jest tu?

Odpowiedz

6

Można użyć not tutaj:

import scala.util.parsing.combinator._ 

object MyParser extends RegexParsers { 
    val keyword = "h1." | "h2." 
    val lineNotStartingWithKeyword = not(keyword) ~> ".*".r 

    def apply(s: String) = parseAll(lineNotStartingWithKeyword, s) 
} 

Teraz:

scala> MyParser("h1. test") 
res0: MyParser.ParseResult[String] = 
[1.1] failure: Expected failure 

h1. test 
^ 

scala> MyParser("h1 test") 
res1: MyParser.ParseResult[String] = [1.8] parsed: h1 test 

Należy pamiętać, że istnieje również failure metoda na Parsers, więc można równie dobrze napisany wersję z keyword ~! failure("keyword!"). Ale i tak not jest o wiele ładniej.