Scala parser-combinators: how to invert matches?
parser-combinators, scala
Solution
You can use `not` here:
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)
}
Now:
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
Note that there is also a `failure` method on `Parsers`, so you could just as well have written your version with `keyword ~! failure("keyword!")`. But `not`'s a lot nicer, anyway.
Problem
Is it possible to invert matches with Scala parser combinators? I am trying to match lines with a parser that do not start with a set of keywords. I could do this with an annoying zero width negative lookahead regular expression (e.g. `"(?!h1|h2).*"`), but I'd rather do it with a Scala parser. The best I've been able to come up with is this: ``` def keyword = "h1." | "h2." def alwaysfails = "(?=a)b".r def linenotstartingwithkeyword = keyword ~! alwaysfails | ".*".r ``` The idea is here that I use ~! to forbid backtracking to the all-matching regexp, and then continue with a regex "(?=a)b".r that matches nothing. (By the way, is there a predefined parser that always fails?) That way the line would not be matched if a keyword is found but would be matched if keyword does not match. I am wondering if there is a better way to do this. Is there?