Как узнать кодировку файла
Перейти к содержимому

Как узнать кодировку файла

  • автор:

Как определить кодировку в текстовом файле (имея в наличии только файл)?

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

Denis211990; + 1 – Ответить
5. ishelper 10.03.22 13:03 Сейчас в теме
без необходимости ввода подстроки поиска

Без строки поиска требуется понимание содержания текста. Вряд ли можно рассчитывать в этом на 1С. 😉

Просто строку поиска нужно задавать программно , подбирая ее по частоте использования в языке, возможно — не одну, например, искать: » и «, » не «, «но » и так далее

Denis211990; + 1 – Ответить
11. dehro 5 29.01.23 09:21 Сейчас в теме

(1)Однозначно: никак. Текстовый файл: набор байтов, разделённых байтом EOL и заканчивающихся байтом EOF. Никакого заголовка, как например у файла архива или exe-шника, у него нет.

Для двухбайтных кодировок вряд ли что изменилось. Просто теперь это последовательность машинных слов (word), а не одиночных байтов.

Все утилиты путём анализа символов (последовательностей, количества, etc) пытаются угадать кодировку.

13. Said-We 27.03.23 19:38 Сейчас в теме
Требуется определить, какая кодировка используется в файле.
Чтобы предупредить пользователя

В идеале никак.
Браузеры свои алгоритмы сложные имеют и то иногда кракозябры открывают.

Но чаще всего это UTF-8. Т.е. каждый символ может занимать от одного байта до 4-х. И всё это в одном и том же тексте. Одновременно.
Английский язык один байт, русский два, грузинский три, азиатские иероглифы 4-ре.

ASCII, КОИ-8, UTF-8 первые символы и английские символы максимально совпадают.
КОИ-7 давно не видел.

6. cargobird 306 30.11.22 12:36 Сейчас в теме

Такую функцию сделал исходя из предположения, что коды символов всех знаков находятся до 100, а коды символов заглавных букв от А до Я находится в диапазоне 1040-1071. Исключение — Ё с кодом 1025.
Так вот, если при чтении файла с заданной кодировкой встречается символ вне указанных диапазонов — то это битый символ, значит кодировка не та надо прочитать файл с другой кодировкой (и так до победного).
Для небольших файлов пригодилось.

Функция ОпределитьКодировкуФайла(ПутьКФайлу) Экспорт мКодировок=Новый Массив; мКодировок.Добавить(КодировкаТекста.ANSI); мКодировок.Добавить(КодировкаТекста.OEM); мКодировок.Добавить(КодировкаТекста.UTF16); мКодировок.Добавить(КодировкаТекста.UTF8); мНайденных=Новый Массив; Для каждого рКодировка Из мКодировок Цикл т=Новый ТекстовыйДокумент; т.Прочитать(ПутьКФайлу,рКодировка); стро=ВРег(т.ПолучитьТекст()); // ВРег это важно Если НЕ НайтиСимволыВнеДиапазона(стро) Тогда // если не найдено ни одного "битого" символа - искомая кодировка Возврат рКодировка; КонецЕсли; КонецЦикла; Возврат КодировкаТекста.ANSI; // по умолчанию КонецФункции Функция НайтиСимволыВнеДиапазона(ТекСтрока) Для Поз = 1 По СтрДлина(ТекСтрока) Цикл ТекКод = КодСимвола(Сред(ТекСтрока, Поз, 1)); Если (ТекКод > 100 // до 100 разные знаки типа % - " и т.д. И ТекКод < 1040 // 1040 код символа А И НЕ ТекКод = 1025) // 1025 код символа Ё (вне диапазона заглавных букв А-Я 1040-1071) ИЛИ ТекКод >1071// 1071 код символа Я Тогда Возврат Истина; КонецЕсли; КонецЦикла; Возврат Ложь; КонецФункции

Denis211990; + 1 – Ответить
7. user1863362 30.11.22 12:46 Сейчас в теме
коды символов всех знаков находятся до 100

Вот скажи честно, ты таблицу ASCII вообще видел? Скобки там разные квадратные, фигурные, не? Битые символы, да?

9. cargobird 306 30.11.22 13:02 Сейчас в теме
(7) до 126 нижний диапазон расширить надо.
Спасибо за подсказку!
8. ImHunter 284 30.11.22 12:48 Сейчас в теме
(1) Определял для XML. Может подойдет .
Denis211990; + 1 – Ответить
10. triviumfan 86 28.01.23 23:40 Сейчас в теме
В ERP есть такое:

// Возвращает наиболее подходящую кодировку текста, полученную путем сравнения с алфавитом. // // Параметры: // ДанныеТекста — ДвоичныеДанные — двоичные данные файла. // // Возвращаемое значение: // Строка — кодировка файла. // Функция КодировкаИзСоответствияАлфавиту(ДанныеТекста) Кодировки = РаботаСФайламиСлужебный.Кодировки(); Кодировки.Удалить(Кодировки.НайтиПоЗначению(«utf-8_WithoutBOM»)); КодировкаKOI8R = Кодировки.НайтиПоЗначению(«koi8-r»); Кодировки.Сдвинуть(КодировкаKOI8R, -Кодировки.Индекс(КодировкаKOI8R)); КодировкаWin1251 = Кодировки.НайтиПоЗначению(«windows-1251»); Кодировки.Сдвинуть(КодировкаWin1251, -Кодировки.Индекс(КодировкаWin1251)); КодировкаUTF8 = Кодировки.НайтиПоЗначению(«utf-8»); Кодировки.Сдвинуть(КодировкаUTF8, -Кодировки.Индекс(КодировкаUTF8)); СоответствующаяКодировка = «»; МаксимальноеСоответствиеКодировки = 0; Для Каждого Кодировка Из Кодировки Цикл СоответствиеКодировки = ПроцентСоответствияАлфавиту(ДанныеТекста, Кодировка.Значение); Если СоответствиеКодировки > 0.95 Тогда Возврат Кодировка.Значение; КонецЕсли; Если СоответствиеКодировки > МаксимальноеСоответствиеКодировки Тогда СоответствующаяКодировка = Кодировка.Значение; МаксимальноеСоответствиеКодировки = СоответствиеКодировки; КонецЕсли; КонецЦикла; Возврат СоответствующаяКодировка; КонецФункции Функция ПроцентСоответствияАлфавиту(ДвоичныеДанные, ПроверяемаяКодировка) // АПК:1036-выкл, АПК:163-выкл — алфавит не требует проверки орфографии. Алфавит + «AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz» + «1234567890 «; // АПК:1036-вкл, АПК:163-вкл ПотокАлфавита = Новый ПотокВПамяти(); ЗаписьАлфавита = Новый ЗаписьДанных(ПотокАлфавита); ЗаписьАлфавита.ЗаписатьСтроку(Алфавит, ПроверяемаяКодировка); ЗаписьАлфавита.Закрыть(); ДанныеАлфавита = ПотокАлфавита.ЗакрытьИПолучитьДвоичныеДанные(); ЧтениеДанныхАлфавита = Новый ЧтениеДанных(ДанныеАлфавита); БуферАлфавитаВКодировке = ЧтениеДанныхАлфавита.ПрочитатьВБуферДвоичныхДанных(); Индекс = 0; СимволыАлфавита = Новый Массив; Пока Индекс Показать

Denis211990; + 1 – Ответить
12. ybatiaev 58 27.03.23 19:13 Сейчас в теме
КодировкаИзСоответствияАлфавиту

так понял, что данной функции надо скармливать файлы с только определёнными именами. По крайней мере в Бух30 так сейчас (

14. triviumfan 86 27.03.23 21:49 Сейчас в теме

(12) Параметр «ДанныеТекста» — двоичные данные. Где там хотя бы слово про формат файла?)
Анализируется сам текст.

15. ybatiaev 58 27.03.23 22:10 Сейчас в теме

(14)
(14) Это я воспользовался стандартной РегистрыСведенийКодирвкиФайлов.ОпределитьКодирвкиФайлов(ПрисоединенныйФайл, Расширение)
Ошибку выдавала 1С не про формат, а про имена файлов. Типа ожидаю вот такие, а мне подсунуто «Тест.txt»

16. user1826630 27.03.23 22:38 Сейчас в теме
Типа ожидаю вот такие, а мне подсунуто «Тест.txt»
Точно! Кодировка текста определяется расширением файла!
17. ybatiaev 58 27.03.23 22:40 Сейчас в теме

(16) расширение задаётся параметром, что не так? И не надо смеяться. Сделал в итоге по Вашему. Стандартную сразу не использую
(16)

18. user1826630 27.03.23 22:52 Сейчас в теме
Сделал в итоге по Вашему.
Я разве предлагал свое решение? Покажите мне его.
расширение задаётся параметром, что не так?
А проблема разве в расширении? Проблема в определении кодировки.
19. ybatiaev 58 27.03.23 23:41 Сейчас в теме
А проблема разве в расширении? Проблема в определении кодировки.

Так и пытаюсь это решить же. Если операционка определяет это чётко, значит как бы можно используя WMI это сделать. Пока не нашёл правильного решения

20. triviumfan 86 28.03.23 14:57 Сейчас в теме

(19) Ничего не понял, причём тут WMI.
Понял, что вы пытались использовать типовую функцию, неверно передав в неё параметр «расширение», хотя оно нужно лишь для частного случая определения кодировки из xml файла по заголовку:)
Вообще я сомневаюсь, что это «определение по алфавиту» работает, я просто нашёл её в одном из решении, проверил работу и всё)

21. ybatiaev 58 28.03.23 15:03 Сейчас в теме
Ничего не понял, причём тут WMI

Это я написал, что ВОЗМОЖНО есть механизмы операционки для определения кодировки. Они 100% есть, т.к. открываешь файл в Виндах — кодировка сразу прописана в строке состояния. У нас. на некоторых серверах не прописана. Т.е. задана системная и, скорее всего, других не используется вообще. Спросил только потому, что может кто-то сталкивался.
Предварительно решил как предложил cargobird(6). Пользователи работают.

Как определить кодировку файла или строки. Как конвертировать файлы в кодировку UTF-8 в Linux

В этой инструкции мы опишем что такое кодировка символов и рассмотрим несколько примеров конвертации файлов из одной кодировки в другую с использованием инструмента командной строки. Наконец, мы узнаем, как на Linux конвертировать несколько файлов из одного набора символов (charset) в UTF-8 кодировку.

Возможно, вы уже в курсе, что компьютер не понимает и не сохраняет буквы, числа или что-то ещё чем обычно оперируют люди. Компьютер работает с битами. Бит имеет только два возможных значения: 0 или 1, «истина» или «ложь», «да» или «нет». Все другие вещи, вроде букв, цифр, изображений должны быть представлены в битах, чтобы компьютер мог их обрабатывать.

Говоря простыми словами, кодировка символов – это способ информирования компьютера о том, как интерпретировать исходные нули и единицы в реальные символы, где символ представлен набором чисел. Когда мы печатаем текст в файле, слова и предложения, которые мы формируем, готовятся из разных символов, а символы упорядочиваются в кодировку.

Имеются различные схемы кодирования, среди них такие как ASCII, ANSI, Unicode. Ниже пример ASCII кодировки.

Символ биты A 01000001 B 01000010

Программы для определения кодировки в Linux

Команда file -i показывает неверную кодировку

Чтобы узнать кодировку файла используется команда file с флагами -i или —mime, которые включают вывод строки с типом MIME. Пример:

file -i mypoem_draft.txt file -i mynovel.txt

Команда file показывает кодировки, но для одного из моих файлов она неверна. Рассмотрим ещё одну альтернативу.

Программа enca для определения кодировки файла

Утилита enca определяет кодировку текстовых файлов и, если нужно, конвертирует их.

Установим программу enca:

sudo apt install enca
enca mypoem_draft.txt enca mynovel.txt

В этот раз для обоих файлов кодировка определена верно.

Запуск команды без опции выводит что-то вроде:

MS-Windows code page 1251 LF line terminators

Это удобно для чтения людьми. Для использования вывода программы в скриптах есть опция -e, она выводит только универсальное имя, используемое в enca:

enca -e mypoem_draft.txt CP1251/LF

Если вам нужно имя, которое используется для названия кодировок в iconv, то для этого воспользуйтесь опцией -i:

enca -i mypoem_draft.txt CP1251

Для вывода предпочитаемого MIME имени кодировки используется опция -m:

enca -m mypoem_draft.txt windows-1251

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

Язык документа можно явно указать опцией -L:

enca -m -L russian mypoem_draft.txt

Чтобы узнать список доступных языков наберите:

enca --list languages
belarusian: CP1251 IBM866 ISO-8859-5 KOI8-UNI maccyr IBM855 KOI8-U bulgarian: CP1251 ISO-8859-5 IBM855 maccyr ECMA-113 czech: ISO-8859-2 CP1250 IBM852 KEYBCS2 macce KOI-8_CS_2 CORK estonian: ISO-8859-4 CP1257 IBM775 ISO-8859-13 macce baltic croatian: CP1250 ISO-8859-2 IBM852 macce CORK hungarian: ISO-8859-2 CP1250 IBM852 macce CORK lithuanian: CP1257 ISO-8859-4 IBM775 ISO-8859-13 macce baltic latvian: CP1257 ISO-8859-4 IBM775 ISO-8859-13 macce baltic polish: ISO-8859-2 CP1250 IBM852 macce ISO-8859-13 ISO-8859-16 baltic CORK russian: KOI8-R CP1251 ISO-8859-5 IBM866 maccyr slovak: CP1250 ISO-8859-2 IBM852 KEYBCS2 macce KOI-8_CS_2 CORK slovene: ISO-8859-2 CP1250 IBM852 macce CORK ukrainian: CP1251 IBM855 ISO-8859-5 CP1125 KOI8-U maccyr chinese: GBK BIG5 HZ none:

Как определить кодировку строки

Для определения, в какой кодировке строка, используйте одну из следующих конструкций:

echo $'СТРОКА_ДЛЯ_ПРОВЕРКИ' | chardet
echo $'СТРОКА_ДЛЯ_ПРОВЕРКИ' | enca -L ru

Вместо СТРОКА_ДЛЯ_ПРОВЕРКИ впишите строку, для которой нужно узнать кодировку. Если у вас строка не на русском языке, то откорректируйте значение опции -L.

echo $'\xed\xe5 \xed\xe0 \xe9\xe4\xe5\xed\xf3\xea \xe0\xe7\xe0\xed\xed\xfb\xe9\xec\xee\xe4\xf3\xeb\xfc' | chardet : windows-1251 with confidence 0.970067019236
echo $'\xed\xe5 \xed\xe0 \xe9\xe4\xe5\xed\xf3\xea \xe0\xe7\xe0\xed\xed\xfb\xe9\xec\xee\xe4\xf3\xeb\xfc' | enca -L ru MS-Windows code page 1251 LF line terminators

Если возникло сообщение об ошибке:

bash: chardet: команда не найдена

то попробуйте установить chardet из стандартных репозиториев.

Если chardet не найдена в репозиториях, то поищите программу uchardet, затем установите и используйте её.

Изменение кодировки в Linux

Использование команды iconv

В Linux для конвертации текста из одной кодировки в другую используется команда iconv.

Синтаксис использования iconv имеет следующий вид:

iconv опция iconv опции -f из-кодировки -t в-кодировку файл(ы) ввода -o файлы вывода

Где -f или —from-code означает кодировку исходного файла -t или —to-encoding указывают кодировку нового файла. Флаг -o является необязательным, если его нет, то содержимое документа в новой кодировке будет показано в стандартном выводе.

Чтобы вывести список всех кодировок, запустите команду:

iconv -l

Конвертирование файлов из windows-1251 в UTF-8 кодировку

Далее мы научимся, как конвертировать файлы из одной схемы кодирования (кодировки) в другую. В качестве примера наша команда будет конвертировать из windows-1251 (которая также называется CP1251) в UTF-8 кодировку.

Допустим, у нас есть файл mypoem_draft.txt его содержимое выводится как

Мы начнём с проверки кодировки символов в файле, просмотрим содержимое файла, выполним конвертирование и просмотрим содержимое файла ещё раз.

enca -i mypoem_draft.txt cat mypoem_draft.txt iconv -f CP1251 -t UTF-8//TRANSLIT mypoem_draft.txt -o poem.txt cat poem.txt enca -i poem.txt

Примечание: если к кодировке, в который мы конвертируем файл добавить строку //IGNORE, то символы, которые невозможно конвертировать, будут отбрасываться и после конвертации показана ошибка.

Если к конечной кодировке добавляется строка //TRANSLIT, конвертируемые символы при необходимости и возможности будут транслитерированы. Это означает, когда символ не может быть представлен в целевом наборе символов, он может быть заменён одним или несколькими выглядящими похоже символами. Символы, которые вне целевого набора символов и не могут быть транслитерированы, в выводе заменяются знаком вопроса (?).

Изменение кодировки программой enca

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

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

cp mypoem_draft.txt mypoem_draft.txt.bac

Желаемую кодировку нужно указать после ключа -x:

enca -x UTF-8 mypoem_draft.txt

Конвертация строки в правильную кодировку

Команда iconv может конвертировать строки в нужную кодировку. Для этого строка передаётся по стандартному вводу. Достаточно использовать только опцию -f для указания кодировки, в которую должна быть преобразована строка. Т.е. используется команда следующего вида:

echo $'СТРОКА_ДЛЯ_ИЗМЕНЕНИЯ_КОДИРОВКИ' | iconv -f 'ЖЕЛАЕМАЯ_КОДИРОВКА'
echo $'\xed\xe5 \xed\xe0\xe9\xe4\xe5\xed \xf3\xea\xe0\xe7\xe0\xed\xed\xfb\xe9 \xec\xee\xe4\xf3\xeb\xfc' | iconv -f 'Windows-1251' не найден указанный модуль

Также для изменения кодировки применяются программы:

Как узнать кодировку текста онлайн?

Существует ряд сервисов, которые способны определить кодировку текста онлайн. Они все делают автоматически, в том числе позволяют конвертировать слова в правильный формат. Хотя подобных сервисов много, не все они одинаково хорошо подходят для определения кодировки онлайн. Мы подобрали несколько лучших вариантов.

Online Decoder

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

Что нужно сделать:

  1. Открывать сайт Online Decoder.
  2. Вставляем в пустое поле наш текст с неправильной кодировкой.
  3. В строке «Раскодировать текст автоматически (рекомендуется)» нажимаем на кнопку «Подбор».
  4. Немного ниже, в строке «Я знаю нужные кодировки» обращаем внимание на первую часть. Там указана кодировка вставленного текста, а во втором поле – та, в которую конвертирован фрагмент.

Определение кодировки онлайн

2cyr

Сервис создан для декодирования различного текста, в том числе он способен преобразовывать строки между различными кодировками. Он довольно прост и не требует никаких особенных знаний. Вам достаточно открыть сайт 2cyr, вставить текст и нажать на кнопку «Ок» справа под пустым полем. После непродолжительного анализа система выдаст информацию о родной кодировке текста и той, что была установлена после преобразования.

Определение кодировки онлайн

FoxTools

Принцип работы подобен описанным выше сервисам, но есть и одно отличие. Сайт предоставляет большой выбор вариантов текста на выходе. Он предлагает вам самостоятельно найти ту кодировку, в которой текст будет читаться правильно. Это положительная особенность, так как некоторые форматы пересекаются между собой и могут неправильно определяться автоматическими сервисами.

Как это работает:

  1. Переходим на целевую страницу FoxTools.
  2. Вставляем в пустое поле текст и жмем по кнопке «Отправить».
  3. Нажимаем по выпадающему списку с названием «Выберите читаемый вариант из списка» и ищем тот текст, который мы можем без проблем прочитать.

Определение кодировки онлайн

Определение кодировки онлайн – простая задача, особенно с помощью хороших веб-сервисов. Все они бесплатные, простые в использовании и достаточно точны.

Автоопределение кодировки текста

image

Я очень люблю программировать, я любитель и первый и последний раз заработал на программировании в далёком 1996 году. Но для автоматизации повседневных задач иногда что-то пишу. Примерно год назад открыл для себя golang. В качестве инструмента создания утилит golang оказался очень удобным. Итак.

Возникла потребность обработать большое количество (больше тысячи, так и вижу улыбки профи) архивных файлов со специальной геофизической информацией. Формат файлов текстовый, простой. Если вдруг интересно то это LAS формат.
LAS файл содержит заголовок и данные.

Данные практически CSV, только разделитель табуляция или пробелы.

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

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

В итоге изобрёл велосипед на golang и соответственно родилась маленькая библиотечка с возможностью детектировать кодовую страницу.

Про кодировки. Не так давно на хабре была хорошая статья про кодировки Как работают кодировки текста. Откуда появляются «кракозябры». Принципы кодирования. Обобщение и детальный разбор Если хочется понять, что такое “кракозябры” или “кости”, то стоит прочитать.

В начале я накидал своё решение. Потом пытался найти готовое работающее решение на golang, но не вышло. Нашлось два решения, но оба не работают.

  • Первое “из коробки”— golang.org/x/net/html/charset функция DetermineEncoding()
  • Второе библиотека — saintfish/chardet на github

Обе уверенно ошибаются на некоторых кодировках. Стандартная та вообще почти ничего определить не может по текстовым файлам, оно и понятно, её для html страниц делали.

При поиске часто натыкался на готовые утилиты из мира linux — enca. Нашёл её версию скомпилированную для WIN32, версия 1.12. Её я тоже рассмотрю, там есть забавности. Я прошу сразу прощения за своё полное незнание linux, а значит возможно есть ещё решения которые тоже можно попытаться прикрутить к golang коду, я больше искать не стал.

Сравнение найденных решений на автоопределение кодировки

Подготовил каталог softlandia\cpd тестовые данные с файлами в разных кодировках. Содержимое файлов очень короткое и одинаковое. Одна строка “Русский в кодировке CodePageName”. Дополнил файлами со смешением кодировок и некоторыми сложными случаями и попробовал определить.

Мне кажется, получилось забавно.

# Кодировка html/charset saintfish/chardet softlandia/cpd enca
1 CP1251 windows-1252 CP1251 CP1251 CP1251
2 CP866 windows-1252 windows-1252 CP866 CP866
3 KOI8-R windows-1252 KOI8-R KOI8-R KOI8-R
4 ISO-8859-5 windows-1252 ISO-8859-5 ISO-8859-5 ISO-8859-5
5 UTF-8 with BOM utf-8 utf-8 utf-8 utf-8
6 UTF-8 without BOM utf-8 utf-8 utf-8 utf-8
7 UTF-16LE with BOM utf-16le utf-16le utf-16le ISO-10646-UCS-2
8 UTF-16LE without BOM windows-1252 ISO-8859-1 utf-16le unknown
9 UTF-16BE with BOM utf-16le utf-16be utf-16be ISO-10646-UCS-2
10 UTF-16BE without BOM windows-1252 ISO-8859-1 utf-16be ISO-10646-UCS-2
11 UTF-32LE with BOM utf-16le utf-32le utf-32le ISO-10646-UCS-4
12 UTF-32LE without BOM windows-1252 utf-32le utf-32le ISO-10646-UCS-4
13 UTF-32BE with BOM windows-1252 utf-32be utf-32be ISO-10646-UCS-4
14 UTF-32BE without BOM windows-1252 utf-32be utf-32be ISO-10646-UCS-4
15 KOI8-R (UPPER) windows-1252 KOI8-R KOI8-R CP1251
16 CP1251 (UPPER) windows-1252 CP1251 CP1251 KOI8-R
17 CP866 & CP1251 windows-1252 CP1251 CP1251 unknown

Наблюдение 1

enca не определила кодировку у файла UTF-16LE без BOM — это странно, ну ладно. Я попробовал добавить больше текста, но результата не получил.

Наблюдение 2. Проблемы с кодировками CP1251 и KOI8-R

Строка 15 и 16. У команды enca есть проблемы.
Здесь сделаю объяснение, дело в том, что кодировки CP1251 (она же Windows 1251) и KOI8-R очень близки если рассматривать только алфавитные символы.

Таблица CP 1251

image

Таблица KOI8-r

image

В обеих кодировках алфавит расположен от 0xC0 до 0xFF, но там, где у одной кодировки заглавные буквы, у другой строчные. Судя по всему enca, работает по строчным буквам. Вот и получается, если подать на вход программе enca строку “СТП” в кодировке CP1251, то она решит, что это строка “яро” в кодировке KOI8-r, о чём и сообщит. В обратную сторону также работает.

Наблюдение 3

Стандартной библиотеке html/charset можно доверить только определение UTF-8, но осторожно! Пользоваться следует именно charset.DetermineEncoding(), поскольку метод utf8.Valid(b []byte) на файлах в кодировке utf-16be возвращает true.

Собственный велосипед

image

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

Для меня такая цель не стояла. Мне достаточно определять кодировки в предположении, что там есть русский язык. И второе, определять нужно по небольшому количеству символов – на 10 символах должно быть достаточно уверенное определение, а желательно вообще на 5–6 символах.

Алгоритм

Когда я обнаружил совпадение кодировок KOI8-r и CP1251 по местоположению алфавита, то на пару дней загрустил… стало понятно, что чуть-чуть придётся подумать. Получилось так.

  1. Работу будем вести со слайсом байтов, для совместимости с charset.DetermineEncoding()
  2. Кодировку UTF-8 и случаи с BOM проверяем отдельно
  3. Входные данные передаём по очереди каждой кодировке. Каждая сама вычисляет два целочисленных критерия. У кого сумма двух критериев больше, тот и выиграл.

Критерии соответствия

Первый критерий

Первым критерием является количество самых популярных букв русского алфавита.

Наиболее часто встречаются буквы: о, е, а, и, н, т, с, р, в, л, к, м, д, п, у. Данные буквы дают 82% покрытия. Для всех кодировок кроме KOI8-r и CP1251 я использовал только первые 9 букв: о, е, а, и, н, т, с, р, в. Этого вполне хватает для уверенного определения.

А вот для KOI8-r и CP1251 пришлось доработать напильником. Коды некоторых из этих букв совпадают, например буква о имеет в CP1251 код 0xEE при этом в KOI8-r этот код у буквы н. Для этих кодировок были взяты следующие популярные буквы. Для CP1251 использовал а, и, н, с, р, в, л, к, я. Для KOI8-r — о, а, и, т, с, в, л, к, м.

Второй критерий

К сожалению, для очень коротких случаев (общая длина русского текста 5-6 символов) встречаемость популярных букв на уровне 1-3 шт и происходит нахлёст кодировок KOI8-r и CP1251. Пришлось вводить второй критерий. Подсчёт количества пар согласная+гласная.
Такие комбинации ожидаемо наиболее часто встречаются в русском языке и соответственно в той кодировке в которой число таких пар больше, та кодировка имеет больший критерий.

Вычисляются оба критерия, складываются и полученная сумма является итоговым критерием.
Результат отражен в таблице выше.

Особенности, с которыми я столкнулся

Чуть коснусь прелестей и проблем, связанных с golang. Раздел может быть интересен только начинающим писать на golang.

Проблемы

Лично походил по некоторым подводным камушкам из 50 оттенков Go: ловушки, подводные камни и распространённые ошибки новичков.
Излишне переживая и пытаясь дуть на воду, прослышав от других о страшных ожогах от молока, переборщил с проверкой входного параметра типа io.Reader. Я проверял переменную типа io.Reader с помощью рефлексии.

//CodePageDetect - detect code page of ascii data from reader 'r' func CodePageDetect(r io.Reader, stopStr . string) (IDCodePage, error) < if !reflect.ValueOf(r).IsValid() < return ASCII, fmt.Errorf("input reader is nil") >. 

Но как оказалось в моём случае достаточно проверить на nil. Теперь всё стало проще

func CodePageDetect(r io.Reader, stopStr . string) (IDCodePage, error) < //test input interfase if r == nil < return ASCII, nil >//make slice of byte from input reader buf, err := bufio.NewReader(r).Peek(ReadBufSize) if (err != nil) && (err != io.EOF) < return ASCII, err >. 

вызов bufio.NewReader( r ).Peek(ReadBufSize) спокойно проходит следующий тест:

 var data *os.File res, err := CodePageDetect(data)

В этом случае Peek() возвращает ошибку.

Разок наступил на грабли с передачей массивов по значению. Немного тупанул на попытке изменять элементы, хранящиеся в map, пробегая по ним в range…

Прелести

Сложно сказать что конкретно, постоянное ли битьё по рукам от линтера и компилятора или активное использование range, или всё вместе, но практически отсутствуют залёты по выходу индекса за пределы.

Конечно, очень приятно жить со сборщиком мусора. Полагаю мне ещё предстоит освоить грабли автоматизации выделения/освобождения памяти, но пока дебильная улыбка не покидает лица.
Строгая типизация — тоже кусочек счастья.

Переменные, имеющие тип функции — соответственно лёгкая реализация различного поведения у однотипных объектов.

Странно мало пришлось сидеть в отладчике, перечитывание кода обычно даёт результат.

Щенячий восторг от наличия массы инструментов из коробки, это чудное ощущение, когда компилятор, язык, библиотека и IDE Visual Studio Code работают на тебя вместе, слаженно.

Спасибо falconandy за конструктивные и полезные советы
Благодаря ему

  1. перевёл тесты на testify и они действительно стали более читабельны
  2. исправил в тестах пути к файлам данных для совместимости с Linux
  3. прошёлся линтером — таки он нашёл одну реальную ошибку (проклятущий copy/past)

Продолжаю добавлять тесты, выявился случай не определения UTF16. Обновил. Теперь UTF16 и LE и BE определяются даже в случае отсутствия русских букв

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *