2016-11-06 2 views
1

Ich bin eine Ressource-Datei und die Aufteilung auf Leerzeilen-Parsing, mit dem folgenden Code:Scala regex Spaltung auf Input

val inputStream = getClass.getResourceAsStream("foo.txt") 
val source = scala.io.Source.fromInputStream(inputStream) 
val fooString = source.mkString 
val fooParsedSections = fooString.split("\\r\\n[\\f\\t ]*\\r\\n") 

Ich glaube, das den Eingangsstrom in dem Speicher als vollständige Zeichenfolge zieht, und dann Aufteilen auf die Regex. Dies funktioniert gut für die relativ kleine Datei, ich bin Parsen, aber es ist nicht ideal, und ich bin gespannt, wie ich es--

Zwei Ideen verbessern könnte:

  1. lesen Sie die Eingabe-Stream Line-by -Linie und einen Puffer von Segmenten, die ich aufbauen, Splitting auf Leerzeilen
  2. lesen den Strom Zeichen-für-Zeichen und Segmente aus einer kleinen endlichen Automaten

jedoch basiert analysieren, würde ich Ich liebe es, wenn möglich keinen veränderbaren Puffer zu pflegen.

Irgendwelche Vorschläge? Dies ist nur für ein persönliches Spaßprojekt, und ich möchte lernen, wie man das auf eine effiziente und funktionelle Weise macht.

Antwort

1

Sie können Stream.span Methode verwenden, um das Präfix vor der leeren Zeile zu erhalten, dann wiederholen. Hier ist eine Hilfsfunktion für das:

def sections(lines: Stream[String]): Stream[String] = { 
    if (lines.isEmpty) Stream.empty 
    else { 
    // cutting off the longest `prefix` before an empty line 
    val (prefix, suffix) = lines.span { _.trim.nonEmpty } 
    // dropping any empty lines (there may be several) 
    val rest = suffix.dropWhile{ _.trim.isEmpty } 

    // grouping back the prefix lines and calling recursion 
    prefix.mkString("\n") #:: sections(rest) 
    } 
} 

Hinweis, dass Stream ‚s Methode #:: faul ist und nicht den rechten Operanden nicht auswertet, bis es gebraucht wird. Hier ist, wie Sie es zu Ihrem Anwendungsfall anwenden können:

val inputStream = getClass.getResourceAsStream("foo.txt") 
val source = scala.io.Source.fromInputStream(inputStream) 
val parsedSections = sections(source.getLines.toStream) 

Source.getLines Methode gibt Iterator[String] die wir Stream wandeln und die Hilfsfunktion anwenden. Sie können auch am Ende .toIterator aufrufen, wenn Sie die Liniengruppen auf dem Weg bearbeiten und nicht speichern müssen. Einzelheiten finden Sie in der Dokumentation Stream.

EDIT

Wenn Sie noch regex verwenden möchten, können Sie .trim.nonEmpty in der Funktion über die Verwendung des Stringmatches Methode ändern.