2016-08-18 3 views
0

Ich möchte die folgenden Testdaten analysieren: Es funktioniert für 3 Fall, also denke ich, dass es ein Problem in meiner Regex gibt. Wenn eine Zeile mit einem # beginnt und ein Kommentar, der ebenfalls mit einem # beginnt, nicht mehr funktioniert. Kann jemand erklären warum? Hier ist meine Lösung so weit ...Wie analysiert man eine Textdatei korrekt mit einem RegexParser?

val testDate = 
    """ 
    |127.0.0.1 ads234.com 
    |#127.0.0.1 auto.search.msn.com # Microsoft uses this server to redirect 
    |#127.0.0.1 sitefinder.verisign.com # Verisign has joined the game 
    |#127.0.0.1 sitefinder-idn.verisign.com # of trying to hijack mistyped 
    |#127.0.0.1 s0.2mdn.net  # This may interfere with some streaming 
    |#127.0.0.1 ad.doubleclick.net # This may interfere with www.sears.com 
    |127.0.0.1 media.fastclick.net # Likewise, this may interfere with some 
    |127.0.0.1 cdn.fastclick.net 
    """.stripMargin 

ich die # und den Kommentar halten wollen, wenn es irgendwelche gibt.

object Example extends RegexParsers { 
    def comment: Parser[String] = """#.*""".r 
    def url: Parser[String] = """[A-Za-z0-9-\.\_\-]{1,65}(?<!-)\.+[A-Za-z]{2,7}""".r 
    def localhost: Parser[String] = """\b(\d{1,3}\.){3}\d{1,3}\b""".r 
    def pound: Parser[String] = "#".r 
    def port: Parser[String] = """:\d{3}""".r 

    def urlPort = url | url <~ port 

    def pos1 = localhost ~ urlPort ^^ { 
    case _ ~ dns => LineParsed("", dns, "") 
    } 
    def pos2 = pound ~ localhost ~ urlPort ^^ { 
    case p ~ _ ~ dns => LineParsed(p, dns, "") 
    } 
    def pos3 = localhost ~ urlPort ~ comment ^^ { 
    case _ ~ dns ~ com => LineParsed("", dns, com) 
    } 
    def pos4 =enter code here pound ~ localhost ~ urlPort ~ comment ^^ { 
    case p ~ _ ~ dns ~ com => LineParsed(p, dns, com) 
    } 

    def linePos = pos1 | pos2 | pos3 | pos4 

    def fullLine = repsep(linePos, """\W*""".r) 
} 

Haben Sie die folgende Ausnahme:

#127.0.0.1 auto.search.msn.com # Microsoft uses this server to redirect 

           ^
    java.lang.RuntimeException: No result when parsing failed 

Antwort

1

ein paar Fehler im Code Es gibt keine. Erstens werden Newline-Zeichen standardmäßig als Whitespaces gezählt, aber Sie müssen sie sehen, um Einträge korrekt zu brechen. So müssen Sie Whitespaces neu definieren:

object Example extends RegexParsers { 
    override protected val whiteSpace: Regex = "[ \t]+".r 

Der fullLine Parser wird dann geschrieben als:

//allow several empty lines at the beginning and between entries 
    def fullLine = rep("\n") ~> repsep(linePos, rep1("\n")) 

(Eine andere Möglichkeit wäre, die Leitung vorher zu spalten und analysieren sie einzeln)

Die nächste Fehler ist die Art, wie Sie Parser mit | kombinieren. Um A zu analysieren, optional gefolgt von B, schreiben Sie nicht A | A ~ B. Es wird nie versuchen, eine B nach dem Lesen einer A zu lesen, weil die linke Seite bereits ein Erfolg ist. Schreiben Sie stattdessen: A ~ B.?

def urlPort = url <~ port.? // But anyway, you'll neve have a port in a host file ! 

In gleicher Weise werden die 4 Fälle pos1 | pos2 | pos3 | pos4 kann stark vereinfacht werden:

def linePos = pound.? ~ localhost ~ urlPort ~ comment.? ^^ { 
    case p ~ _ ~ dns ~ com ⇒ LineParsed(p.getOrElse(""), dns,com.getOrElse("")) 
    } 

Sie können hier sehen, wie die ? combinator Sie eine Option für p und com gibt zurück. Ich benutze getOrElse, um in die Struktur von LineParsed zu passen und das ursprüngliche Verhalten Ihres Codes beizubehalten, aber ein viel mehr scala-ish Ansatz wäre, es als eine Option in der LineParsed Klasse zu behalten.

Hier ist der letzte Arbeitscode, der Ihr Beispiel parst:

object Example extends RegexParsers { 
    override protected val whiteSpace: Regex = "[ \t]+".r 
    def comment: Parser[String] = """#.*""".r 
    def url: Parser[String] = """[A-Za-z0-9-\.\_\-]{1,65}(?<!-)\.+[A-Za-z]{2,7}""".r 
    def localhost: Parser[String] = """\b(\d{1,3}\.){3}\d{1,3}\b""".r 
    def pound: Parser[String] = "#".r 
    def port: Parser[String] = """:\d{3}""".r 
    def urlPort = url <~ port.? 

    def linePos = pound.? ~ localhost ~ urlPort ~ comment.? ^^ { 
    case p ~ _ ~ dns ~ com ⇒ LineParsed(p.getOrElse(""), dns, com.getOrElse("")) 
    } 

    def fullLine = rep("\n") ~> repsep(linePos, rep1("\n")) 
} 
+0

Vielen Dank für Ihre Eingabe. Ich habe versucht, den verbesserten Code auszuführen, aber jetzt bekomme ich eine Exception, die sagt "[10.3] failure: string matching regex" \ b (\ d {1,3} \.) {3} \ d {1,3} \ b ' erwartet aber Ende der Quelle gefunden ". – User1232187

+0

Verwenden Sie 'parse' anstelle von' parseAll' oder erlauben Sie leere Zeilen am Ende des fullLine-Parsers – thibr

Verwandte Themen