Ich habe ein Programm, um sehr große Dateien zu verarbeiten. Jetzt muss ich einen Fortschrittsbalken anzeigen, um den Fortschritt der Verarbeitung anzuzeigen. Das Programm arbeitet auf einer Wortebene, liest Zeile für Zeile, teilt sie in Wörter auf und verarbeitet die Wörter nacheinander. Während also das Programm läuft, kennt es die Anzahl der verarbeiteten Wörter. Wenn es die Wortzählung der Datei vorher irgendwie kennt, kann es den Fortschritt leicht berechnen.Schätzung der Wortzählung einer Datei ohne die vollständige Datei zu lesen
Das Problem ist, dass die Dateien, mit denen ich es zu tun habe, sehr groß sein können. Daher ist es keine gute Idee, die Datei zweimal zu verarbeiten, um die Gesamtzahl der Wörter zu ermitteln und den eigentlichen Verarbeitungscode auszuführen.
Also ich versuche, einen Code zu schreiben, der die Wortzählung einer Datei schätzen kann, indem Sie einen kleinen Teil davon lesen. Das ist, was ich mit (in Clojure) kommen:
(defn estimated-word-count [file]
(let [^java.io.File file (as-file file)
^java.io.Reader rdr (reader file)
buffer (char-array 1000)
chars-read (.read rdr buffer 0 1000)]
(.close rdr)
(if (= chars-read -1)
0
(* 0.001 (.length file)
(-> (String. buffer 0 chars-read) tokenize-line count)))))
Dieser Code liest die ersten 1000 Zeichen aus der Datei, erstellt einen String von ihm, tokenizes es Worte zu bekommen, die Worte zählt, und schätzt dann die Wortzahl der Datei durch Multiplikation mit der Länge der Datei und Division durch 1000.
Wenn ich diesen Code auf eine Datei mit englischem Text ausführen, bekomme ich fast korrekte Wortzahl. Aber wenn ich dies mit einer Datei mit Hindi-Text (in UTF-8 kodiert) ausführe, gibt es fast das Doppelte der tatsächlichen Wortzahl zurück.
Ich verstehe, dass dieses Problem wegen der Codierung ist. Gibt es einen Weg, es zu lösen?
SOLUTION
Als suggested by Frank ich die Byteanzahl der ersten 10.000 Zeichen bestimmen und es verwenden, um die Wortanzahl der Datei zu schätzen.
(defn chars-per-byte [^String s]
(/ (count s) ^Integer (count (.getBytes s "UTF-8"))))
(defn estimate-file-word-count [file]
(let [file (as-file file)
rdr (reader file)
buffer (char-array 10000)
chars-read (.read rdr buffer 0 10000)]
(.close rdr)
(if (= chars-read -1)
0
(let [s (String. buffer 0 chars-read)]
(* (/ 1.0 chars-read) (.length file) (chars-per-byte s)
(-> s tokenize-line count))))))
Beachten Sie, dass dabei UTF-8-Codierung angenommen wird. Außerdem habe ich entschieden, die ersten 10000 Zeichen zu lesen, weil es eine bessere Schätzung gibt.
Ich glaube, Sie sind Tokenizing mit Leerzeichen (ich bin nicht vertraut mit Glojure), das ist ein ziemlich häufiger Fehler. Nicht jede Sprache verwendet Leerräume (oder irgendetwas anderes) für Wortgrenzen. – whiskeysierra
@ WilliSchönborn: Ich bin nicht Tokens mit Leerzeichen. Ich verwende die Unicode-Eigenschaft regex '[\\ p {Z} \\ p {C} \\ p {P}] +'. –
Ah, ok. Seltsame Syntax. – whiskeysierra