2012-10-31 9 views
5

È possibile invertire le corrispondenze con i combinatori di parser Scala? Sto cercando di abbinare le righe con un parser che fa non inizia con una serie di parole chiave. Potrei farlo con una fastidiosa espressione regolare di lookahead negativa a larghezza zero (ad esempio "(?!h1|h2).*"), ma preferirei farlo con un parser di Scala. La cosa migliore che ho trovato è questa:Combinatori di parser alla scala: come invertire le corrispondenze?

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

L'idea è qui che io uso ~! per proibire il backtracking alla regexp di tutte le corrispondenze, e quindi continuare con un'espressione regolare "(? = a) b" .r che non corrisponde a nulla. (A proposito, c'è un parser predefinito che fallisce sempre?) In questo modo la linea non verrebbe abbinata se venisse trovata una parola chiave, ma sarebbe abbinata se la parola chiave non corrispondesse.

Mi chiedo se c'è un modo migliore per farlo. È lì?

risposta

6

È possibile utilizzare not qui:

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) 
} 

Ora:

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 

Nota che c'è anche un metodo failure su Parsers, così si potrebbe altrettanto bene hai scritto la versione con keyword ~! failure("keyword!"). Ma lo not è molto più bello, comunque.

Problemi correlati