Как определить кодировку в текстовом файле (имея в наличии только файл)?
По теме из базы знаний
Ответы
Подписаться на ответы
Инфостарт бот
Сортировка:
Древо развёрнутое
Свернуть все
(3)
без необходимости ввода подстроки поиска
Все зависит от характера файла. Кодировка - это интерпретация только русских букв (и прочих знаков национальных алфавитов, отличных от латиницы, цифр и знаков препинания, ...). В итоге единственная мера - открыть файл в разных кодировках и найти русские буквы там, где они должны быть исходя из характера данных.
(3)
Просто строку поиска нужно задавать программно, подбирая ее по частоте использования в языке, возможно - не одну, например, искать: " и ", " не ", "но " и так далее
без необходимости ввода подстроки поиска
Без строки поиска требуется понимание содержания текста. Вряд ли можно рассчитывать в этом на 1С. ;-)
Просто строку поиска нужно задавать программно, подбирая ее по частоте использования в языке, возможно - не одну, например, искать: " и ", " не ", "но " и так далее
(1)Однозначно: никак. Текстовый файл: набор байтов, разделённых байтом EOL и заканчивающихся байтом EOF. Никакого заголовка, как например у файла архива или exe-шника, у него нет.
Для двухбайтных кодировок вряд ли что изменилось. Просто теперь это последовательность машинных слов (word), а не одиночных байтов.
Все утилиты путём анализа символов (последовательностей, количества, etc) пытаются угадать кодировку.
Для двухбайтных кодировок вряд ли что изменилось. Просто теперь это последовательность машинных слов (word), а не одиночных байтов.
Все утилиты путём анализа символов (последовательностей, количества, etc) пытаются угадать кодировку.
(1)
В идеале никак.
Браузеры свои алгоритмы сложные имеют и то иногда кракозябры открывают.
Но чаще всего это UTF-8. Т.е. каждый символ может занимать от одного байта до 4-х. И всё это в одном и том же тексте. Одновременно.
Английский язык один байт, русский два, грузинский три, азиатские иероглифы 4-ре.
ASCII, КОИ-8, UTF-8 первые символы и английские символы максимально совпадают.
КОИ-7 давно не видел.
Требуется определить, какая кодировка используется в файле.
Чтобы предупредить пользователя
Чтобы предупредить пользователя
В идеале никак.
Браузеры свои алгоритмы сложные имеют и то иногда кракозябры открывают.
Но чаще всего это UTF-8. Т.е. каждый символ может занимать от одного байта до 4-х. И всё это в одном и том же тексте. Одновременно.
Английский язык один байт, русский два, грузинский три, азиатские иероглифы 4-ре.
ASCII, КОИ-8, UTF-8 первые символы и английские символы максимально совпадают.
КОИ-7 давно не видел.
Такую функцию сделал исходя из предположения, что коды символов всех знаков находятся до 100, а коды символов заглавных букв от А до Я находится в диапазоне 1040-1071. Исключение - Ё с кодом 1025.
Так вот, если при чтении файла с заданной кодировкой встречается символ вне указанных диапазонов - то это битый символ, значит кодировка не та надо прочитать файл с другой кодировкой (и так до победного).
Для небольших файлов пригодилось.
Так вот, если при чтении файла с заданной кодировкой встречается символ вне указанных диапазонов - то это битый символ, значит кодировка не та надо прочитать файл с другой кодировкой (и так до победного).
Для небольших файлов пригодилось.
Функция ОпределитьКодировкуФайла(ПутьКФайлу) Экспорт
мКодировок=Новый Массив;
мКодировок.Добавить(КодировкаТекста.ANSI);
мКодировок.Добавить(КодировкаТекста.OEM);
мКодировок.Добавить(КодировкаТекста.UTF16);
мКодировок.Добавить(КодировкаТекста.UTF8);
мНайденных=Новый Массив;
Для каждого рКодировка Из мКодировок Цикл
т=Новый ТекстовыйДокумент;
т.Прочитать(ПутьКФайлу,рКодировка);
стро=ВРег(т.ПолучитьТекст()); // ВРег это важно
Если НЕ НайтиСимволыВнеДиапазона(стро) Тогда
// если не найдено ни одного "битого" символа - искомая кодировка
Возврат рКодировка;
КонецЕсли;
КонецЦикла;
Возврат КодировкаТекста.ANSI; // по умолчанию
КонецФункции
Функция НайтиСимволыВнеДиапазона(ТекСтрока)
Для Поз = 1 По СтрДлина(ТекСтрока) Цикл
ТекКод = КодСимвола(Сред(ТекСтрока, Поз, 1));
Если (ТекКод > 100 // до 100 разные знаки типа % - " и т.д.
И ТекКод < 1040 // 1040 код символа А
И НЕ ТекКод = 1025) // 1025 код символа Ё (вне диапазона заглавных букв А-Я 1040-1071)
ИЛИ ТекКод > 1071// 1071 код символа Я
Тогда
Возврат Истина;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
Показать
В 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;
СимволыАлфавита = Новый Массив;
Пока Индекс <= БуферАлфавитаВКодировке.Размер - 1 Цикл
ТекущийСимвол = БуферАлфавитаВКодировке[Индекс];
// Символы кириллицы в кодировке UTF-8 - двухбайтовые.
Если ПроверяемаяКодировка = "utf-8"
И (ТекущийСимвол = 208
Или ТекущийСимвол = 209) Тогда
Индекс = Индекс + 1;
ТекущийСимвол = Формат(ТекущийСимвол, "ЧН=0; ЧГ=") + Формат(БуферАлфавитаВКодировке[Индекс], "ЧН=0; ЧГ=");
КонецЕсли;
Индекс = Индекс + 1;
СимволыАлфавита.Добавить(ТекущийСимвол);
КонецЦикла;
ЧтениеДанныхТекста = Новый ЧтениеДанных(ДвоичныеДанные);
БуферДанныхТекста = ЧтениеДанныхТекста.ПрочитатьВБуферДвоичныхДанных(?(ПроверяемаяКодировка = "utf-8", 200, 100));
РазмерБуфераТекста = БуферДанныхТекста.Размер;
КоличествоСимволов = РазмерБуфераТекста;
Индекс = 0;
КоличествоВхождений = 0;
Пока Индекс <= РазмерБуфераТекста - 1 Цикл
ТекущийСимвол = БуферДанныхТекста[Индекс];
Если ПроверяемаяКодировка = "utf-8"
И (ТекущийСимвол = 208
Или ТекущийСимвол = 209) Тогда
// Если последний байт в буфере является первым байтом двухбайтового символа, игнорируем его.
Если Индекс = РазмерБуфераТекста - 1 Тогда
Прервать;
КонецЕсли;
Индекс = Индекс + 1;
КоличествоСимволов = КоличествоСимволов - 1;
ТекущийСимвол = Формат(ТекущийСимвол, "ЧН=0; ЧГ=") + Формат(БуферДанныхТекста[Индекс], "ЧН=0; ЧГ=");
КонецЕсли;
Индекс = Индекс + 1;
Если СимволыАлфавита.Найти(ТекущийСимвол) <> Неопределено Тогда
КоличествоВхождений = КоличествоВхождений + 1;
КонецЕсли;
КонецЦикла;
Возврат ?(КоличествоСимволов = 0, 100, КоличествоВхождений/КоличествоСимволов);
КонецФункции
Показать
(19) Ничего не понял, причём тут WMI.
Понял, что вы пытались использовать типовую функцию, неверно передав в неё параметр "расширение", хотя оно нужно лишь для частного случая определения кодировки из xml файла по заголовку:)
Вообще я сомневаюсь, что это "определение по алфавиту" работает, я просто нашёл её в одном из решении, проверил работу и всё)
Понял, что вы пытались использовать типовую функцию, неверно передав в неё параметр "расширение", хотя оно нужно лишь для частного случая определения кодировки из xml файла по заголовку:)
Вообще я сомневаюсь, что это "определение по алфавиту" работает, я просто нашёл её в одном из решении, проверил работу и всё)
(20)
(20)
Это я написал, что ВОЗМОЖНО есть механизмы операционки для определения кодировки. Они 100% есть, т.к. открываешь файл в Виндах - кодировка сразу прописана в строке состояния. У нас. на некоторых серверах не прописана. Т.е. задана системная и, скорее всего, других не используется вообще. Спросил только потому, что может кто-то сталкивался...
Предварительно решил как предложил cargobird(6). Пользователи работают...
(20)
Ничего не понял, причём тут WMI
Это я написал, что ВОЗМОЖНО есть механизмы операционки для определения кодировки. Они 100% есть, т.к. открываешь файл в Виндах - кодировка сразу прописана в строке состояния. У нас. на некоторых серверах не прописана. Т.е. задана системная и, скорее всего, других не используется вообще. Спросил только потому, что может кто-то сталкивался...
Предварительно решил как предложил cargobird(6). Пользователи работают...
Вариация на тему через рег выражения
Функция ПолучитьТекстВПравильнойКодировке(ПутьКФайлу) Экспорт
ТабКодировок = Новый ТаблицаЗначений;
ТабКодировок.Колонки.Добавить("Кодировка");
ТабКодировок.Колонки.Добавить("КоличествоОтклонений",Новый ОписаниеТипов("Число"));
ТабКодировок.Добавить().Кодировка = КодировкаТекста.ANSI;
ТабКодировок.Добавить().Кодировка = КодировкаТекста.OEM;
ТабКодировок.Добавить().Кодировка = КодировкаТекста.UTF16;
ТабКодировок.Добавить().Кодировка = КодировкаТекста.UTF8;
ТабКодировок.Добавить().Кодировка = КодировкаТекста.Системная;
ТабКодировок.Добавить().Кодировка = "windows-1251";
ТабКодировок.Добавить().Кодировка = "KOI8-R";
ТабКодировок.Добавить().Кодировка = "cp866";
ТабКодировок.Добавить().Кодировка = "x-mac-cyrillic";
Док=Новый ТекстовыйДокумент;
Для каждого тКодировка Из ТабКодировок Цикл
Док.Прочитать(ПутьКФайлу,тКодировка.Кодировка);
тТекст = Док.ПолучитьТекст();
Найдено = СтрНайтиПоРегулярномуВыражению(тТекст,"[^A-Za-zA-Яа-я0-9\!""#$%&'\(\)*+-.\/\:\;<=>\?@\[\\\]^_\`\{\|\}\~№@\s\n\t]",,,1); //Ищем первое вхождение символа не из диапазона правильных
Если Найдено.НачальнаяПозиция Тогда //если нашли то считаем количество таких отклонений
Пока Найдено.НачальнаяПозиция Цикл
тКодировка.КоличествоОтклонений = тКодировка.КоличествоОтклонений + 1;
Найдено = СтрНайтиПоРегулярномуВыражению(тТекст,"[^A-Za-zA-Яа-я0-9\!""#$%&'\(\)*+-.\/\:\;<=>\?@\[\\\]^_\`\{\|\}\~№@\s\n\t]",,Найдено.НачальнаяПозиция+Найдено.Длина);
КонецЦикла;
Иначе //если не нашли то возвращаем текст в правильной кодировке
Возврат тТекст;
КонецЕсли;
КонецЦикла;
ТабКодировок.Сортировать("КоличествоОтклонений");//Сортируем таблицу по количеству отклонений
Док.Прочитать(ПутьКФайлу,ТабКодировок[0].Кодировка);//и там где меньше отклонений считаем правильной
Возврат Док.ПолучитьТекст();
КонецФункции
Показать
Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот