매우 큰 파일을 처리하는 프로그램이 있습니다. 이제 처리 진행 상황을 보여주는 진행률 막대를 표시해야합니다. 이 프로그램은 단어 단위로 작동하고 한 번에 한 줄씩 읽으며 단어 단위로 나누어 하나씩 처리합니다. 따라서 프로그램이 실행되는 동안 처리 된 단어의 수를 알 수 있습니다. 여하튼 파일의 단어 수를 미리 알고 있다면 쉽게 진행 상황을 계산할 수 있습니다.전체 파일을 읽지 않고 파일의 단어 수를 계산하십시오.
문제는 내가 다루는 파일이 매우 클 수 있으므로 파일을 두 번 처리해야합니다. 한번은 총 단어 수를 얻고 그 다음은 실제 처리 코드를 실행하는 것이 좋습니다.
그래서 나는 파일의 일부분을 읽음으로써 파일의 단어 수를 추정 할 수있는 코드를 작성하려고합니다.
(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)))))
이 코드는 파일에서 처음 1000 개 문자를 읽고 그것에서 문자열을 만들고, 단어를 얻을 수를 토큰 화는 단어를 계산 한 후 추정 : 이것은 내가 (Clojure의에서) 함께 온 것입니다 파일의 길이를 파일의 길이에 곱하여 1000으로 나눕니다.
이 코드를 영어 텍스트 파일에서 실행할 때 단어 수는 거의 정확합니다. 그러나 힌디어 텍스트 (UTF-8로 인코딩 됨)로 파일을 실행하면 실제 단어 수가 거의 두 배가됩니다.
이 문제는 인코딩으로 인한 것으로 알고 있습니다. 그래서 그것을 해결할 방법이 있습니까?
솔루션
suggested by Frank, 나는 첫 10000 개 문자의 바이트 수를 결정하고 파일의 단어 수를 추정하는 데 사용합니다.
(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))))))
여기서는 UTF-8 인코딩을 가정합니다. 또한 더 나은 견적을 제공하기 때문에 처음 10000 문자를 읽도록 결정했습니다.
공백을 사용하여 토큰 화하는 것 같습니다. (나는 글로 구어에 익숙하지 않습니다.) 이것은 꽤 일반적인 실수입니다. 모든 언어가 단어 경계에 공백 (또는 다른 것)을 사용하는 것은 아닙니다. – whiskeysierra
@ WilliSchönborn : 나는 공간을 사용하여 토큰을 만들고 있지 않습니다. 유니 코드 속성 regex'[\\ p {Z} \\ p {C} \\ p {P}] +'를 사용하고 있습니다. –
아, 좋아. 이상한 구문. – whiskeysierra