2016-03-19 11 views
0

Ich versuche, eine Daten mit combinator Parser zum Parsen eines Parser zurückzukehren [java.util.Date]Kombination eines Parsers andthen unter Verwendung eines anderen Parser von einem anderen Typ erstellen

ich, dass in zwei Phasen, zunächst , ich ein Jahr mit einem simpleYear Parser analysieren, dann habe ich im Ergebnis dieser einfachen Parser in andthen zu stopfen versuchte, würde ich dann diesen Eingang manipulieren als Ausgang dieses andthen ein parseResult [Datum] haben:

Leider bekomme ich den folgenden Fehler vom Compiler in der Zeile der Deklaration:

 type mismatch; found : 
parser.DateParser.Input ⇒ parser.DateParser.ParseResult[java.util.Date] (which 
    expands to) 
    scala.util.parsing.input.Reader[Char] ⇒ parser.DateParser.ParseResult[java.util. required: parser.DateParser.Parser[java.util.Date] 

hier ist der Code:

object DateParser extends RegexParsers { 
     val formatter: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd") 
     def year = """\d{4}""".r 
     def month: Parser[String] = 
     def day = """[0-2]\d""".r | """3[01]""".r 
     def month = """0\d""".r | """1[0-2]""".r 
     def simpleDate: Parser[String] = 
      (year ~ "-" ~ month ~ "-" ~ day) ^^ 
       { case y ~ "-" ~ m ~ "-" ~ d => y + "-" + m + "-" + d } 

     def date: Parser[Date] = simpleDate andThen { 
      case Success(s, in) => 
       val x: ParseResult[Date] = try { 
        Success(formatter.parse(s), in) 
       } catch { 
        case pe: ParseException => Failure("date format invalid", in) 
       } 
       x 
      case f: Failure => f 
     } 
} 

es, dass nicht eine implizite Konvertierung selbst in einen Parser [Datum] (vielleicht wegen des Versuchs von der Art des Zeitpunkt tun kann, der scala Compiler scheint/fangen?)

Gibt es eine andere Möglichkeit zu tun, was ich tun möchte?

Antwort

1

Parser[T] ist eine Unterklasse einer Funktion Input => ParseResult[T] und die von der Funktion verwendete Methode andThen kommt von der Funktion. Sie übergeben ihm eine Funktion ParseResult[String] => ParseResult[Date], so erhalten Sie Input => ParseResult[Date], die nicht mit dem Typ Parser[Date] übereinstimmen, und deshalb erhalten Sie diesen Fehler.

Aber Sie können einfach eine Funktion des Typs Input => ParseResult[T] in eine Parser Methode umwandeln, um eine Parser[T] zu erhalten. So können Sie date wie folgt definieren:

def date: Parser[Date] = Parser(simpleDate andThen { 
    // Cleaned up `Success` case a bit 
    case Success(s, in) => 
    try Success(formatter.parse(s), in) 
    catch { 
     case pe: ParseException => Failure("date format invalid", in) 
    } 
    // It's better to use `NoSuccess` instead of `Failure`, 
    // to cover the `Error` case as well. 
    case f: NoSuccess => f 
}) 

Das heißt, es ist nicht die beste/sauberste Methode. Wie Sie eine Funktion auf dem Parser Ergebnis nennen wollen es irgendwie zu ändern, können Sie die Parser ‚s Methoden map und flatMap oder deren Äquivalente (map entspricht ^^, flatMap entspricht into und >>) verwenden. Diese haben die gleiche Idee wie map und flatMap von anderen Scala Klassen wie Try oder Future.

In diesem Fall müssen Sie die Möglichkeit eines Fehlers berücksichtigen, so dass Sie flatMap verwenden müssen. Eine Definition von dateflatMap verwendet, kann wie folgt aussehen:

def date: Parser[Date] = simpleDate >> (s => 
    try success(formatter.parse(s)) 
    catch { case pe: ParseException => failure("date format invalid") }) 

Auch können Sie (wenn Sie es selbst nicht schon getan hatte) formatter eingestellt Nicht-nachsichtig zu sein: formatter.setLenient(false). Sonst wird es Dinge wie Parsing 2000-02-31 als der 2. März tun!

+0

Vielen Dank für Ihre großartige Antwort, und auch all die anderen Tipps. Ich frage mich, wie kommt es, dass Sie die Methode apply von Parser auf Input => ParseResult [Date] verwenden und einen Parser [Date] zurückbekommen können? Ich überprüfte die api: http://www.scala-lang.org/api/2.10.3/index.html#scala.util.parsing.combinator.ParsersParser aber es ist nicht sichtbar als legal aufgeführt. – Simonlbc

+1

@Simonlbc Es ist eine Methode in 'Parsers' http://www.scala-lang.org/api/2.10.3/index.html # scala.util.parsing.combinator.Parsers Sie erweitern 'RegexParser', die' Parser' erweitern, so dass Sie es nennen können. – Kolmar