Оценка количества слов файла без чтения полного файла - PullRequest
5 голосов
/ 19 августа 2010

У меня есть программа для обработки очень больших файлов. Теперь мне нужно показать индикатор выполнения, чтобы показать ход обработки. Программа работает на уровне слов, читая по одной строке за раз, разбивая ее на слова и обрабатывая слова по одному. Таким образом, пока программы работают, он знает количество обработанных слов. Если каким-то образом он заранее знает количество слов в файле, он может легко вычислить прогресс.

Проблема в том, что файлы, с которыми я имею дело, могут быть очень большими, и поэтому не рекомендуется обрабатывать файл дважды, один раз, чтобы получить общее количество слов, а затем запустить фактический код обработки.

Итак, я пытаюсь написать код, который может оценить количество слов в файле, прочитав небольшую его часть. Вот что я придумал (в 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)))))

Этот код считывает первые 1000 символов из файла, создает из него строку, маркирует ее для получения слов, подсчитывает слова, а затем оценивает количество слов в файле, умножая его на длину файла и деля его на 1000.

Когда я запускаю этот код в файле с английским текстом, я получаю почти правильное количество слов. Но когда я запускаю это для файла с текстом на хинди (в кодировке UTF-8), он возвращает почти вдвое больше реального числа слов.

Я понимаю, что эта проблема из-за кодировки. Так есть ли способ ее решить?

РЕШЕНИЕ

По предложению Фрэнка я определяю количество байтов первых 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 символов, потому что это дает лучшую оценку.

Ответы [ 4 ]

11 голосов
/ 19 августа 2010

Почему бы просто не сделать индикатор выполнения на основе обработанных байтов вместо количества слов.Вы заранее знаете размер, и тогда основная трудность заключается в получении байтов на слово или байтов на строку при их обработке.

Самый простой способ сделать это для каждой прочитанной строки - использовать * 1003.*, предоставляя кодировку символов, в которую был записан файл, и затем получите длину этого.Возможно, это не самый эффективный способ сделать это, но он будет очень точным и простым для выполнения.

В качестве альтернативы, вы можете читать фиксированное количество байтов за раз, а затем самостоятельно поддерживать буфердля обработки частичных слов и переносов строк.

2 голосов
/ 19 августа 2010

В UTF-8 текст на хинди в среднем составляет около двух байтов на символ. Кажется, вы прочитали 1000 символов и применили вычисление к длине файла в байтах. Таким образом, если вы знаете язык заранее, вы можете компенсировать соотношение символов и байтов.

В противном случае вы можете определить количество байтов первых 100 символов, чтобы оценить соотношение. Я не очень хорошо знаю Clojure, но, может быть, вы можете определить текущую позицию в файле как число байтов с некоторым вариантом функции поиска после того, как прочитали 1000 символов?

0 голосов
/ 19 августа 2010

Насколько точной должна быть ваша шкала прогресса?Я предполагаю, что ответ не "критически важен для точности 0,1%".В этом случае просто проверьте размер файла и его кодировку и используйте жестко закодированный AVG_BYTES_PER_WORD для использования с индикатором выполнения.

0 голосов
/ 19 августа 2010

Разве вы не можете компенсировать среднее число байтов / символ с соотношением чтения-чтения / чтения-байта?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...