Tôi có một chương trình xử lý các tệp rất lớn. Bây giờ tôi cần hiển thị thanh tiến trình để hiển thị tiến trình xử lý. Chương trình hoạt động trên một cấp độ từ, đọc từng dòng một, tách nó thành các từ và xử lý từng từ một. Vì vậy, trong khi các chương trình chạy, nó biết số lượng các từ được xử lý. Nếu bằng cách nào đó nó biết số lượng từ của tập tin trước, nó có thể dễ dàng tính toán tiến độ.Ước tính số lượng từ của một tệp mà không cần đọc toàn bộ tệp
Vấn đề là, các tệp tôi đang xử lý có thể rất lớn và do đó không nên xử lý tệp hai lần, một lần để nhận tổng số từ và tiếp theo để chạy mã xử lý thực.
Vì vậy, tôi đang cố gắng viết mã có thể ước tính số lượng từ của một tệp bằng cách đọc một phần nhỏ của tệp. Đây là những gì tôi đã đưa ra (trong Clojure):
(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)))))
Mã này đọc 1000 ký tự đầu tiên từ tập tin, tạo một String từ nó, tokenizes nó để có được chữ, đếm từ và sau đó ước tính số lượng từ của tệp bằng cách nhân nó với chiều dài của tệp và chia nó theo 1000.
Khi tôi chạy mã này trên một tệp có văn bản tiếng Anh, tôi nhận được số từ gần đúng. Nhưng, khi tôi chạy nó trên một tập tin với văn bản tiếng Hin-ddi (được mã hóa bằng UTF-8), nó trở lại gần gấp đôi số lượng từ thực.
Tôi hiểu rằng vấn đề này là do mã hóa. Vì vậy, có cách nào để giải quyết nó?
SOLUTION
Như suggested by Frank, tôi xác định số byte của 10000 ký tự đầu tiên và sử dụng nó để ước tính số lượng từ của tập tin.
(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))))))
Lưu ý rằng điều này giả định mã hóa UTF-8. Ngoài ra, tôi quyết định đọc 10000 ký tự đầu tiên vì nó cho một ước tính tốt hơn.
Tôi đoán bạn đang thông báo bằng cách sử dụng dấu cách (tôi không quen thuộc với glojure), đây là một lỗi khá phổ biến. Không phải mọi ngôn ngữ đều sử dụng khoảng trắng (hoặc bất kỳ thứ gì khác) cho các ranh giới từ. – whiskeysierra
@ WilliSchönborn: Tôi không thông báo bằng cách sử dụng dấu cách. Tôi đang sử dụng regex thuộc tính Unicode '[\\ p {Z} \\ p {C} \\ p {P}] +'. –
Ah, ok. Cú pháp lạ. – whiskeysierra