Как обнаружить кодирование символов текстового файла?
-
12-10-2019 - |
Вопрос
Я пытаюсь обнаружить, какой кодирование символов используется в моем файле.
Я стараюсь с этим кодом, чтобы получить стандартную кодировку
public static Encoding GetFileEncoding(string srcFile)
{
// *** Use Default of Encoding.Default (Ansi CodePage)
Encoding enc = Encoding.Default;
// *** Detect byte order mark if any - otherwise assume default
byte[] buffer = new byte[5];
FileStream file = new FileStream(srcFile, FileMode.Open);
file.Read(buffer, 0, 5);
file.Close();
if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
enc = Encoding.UTF8;
else if (buffer[0] == 0xfe && buffer[1] == 0xff)
enc = Encoding.Unicode;
else if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
enc = Encoding.UTF32;
else if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76)
enc = Encoding.UTF7;
else if (buffer[0] == 0xFE && buffer[1] == 0xFF)
// 1201 unicodeFFFE Unicode (Big-Endian)
enc = Encoding.GetEncoding(1201);
else if (buffer[0] == 0xFF && buffer[1] == 0xFE)
// 1200 utf-16 Unicode
enc = Encoding.GetEncoding(1200);
return enc;
}
Мои пять первых байтов - 60, 118, 56, 46 и 49.
Есть ли диаграмма, которая показывает, какая кодировка соответствует этим пять первых байтов?
Решение
Вы не можете зависеть от файла, имеющего родитель. UTF-8 не требует этого. А кодировки, не являющиеся юникодом, даже не имеют отношения. Однако есть другие способы обнаружения кодирования.
UTF-32
Bom - 00 00 fe ff (для be) или ff fe 00 00 (для LE).
Но UTF-32 легко обнаружить даже без рода. Это связано с тем, что диапазон точек кода Unicode ограничен U+10FFFF, и, таким образом, единицы UTF-32 всегда имеют шаблон 00 {00-10} xx xx (для be) или xx xx {00-10} 00 (для le) Анкет Если данные имеют длину, которая кратно 4, и следует за одним из этих шаблонов, вы можете безопасно предположить, что это UTF-32. Ложные позитивы практически невозможно из-за редкости 00 байтов в байто-ориентированных кодировках.
US-ASCII
Нет, но вам не нужно. ASCII может быть легко идентифицирован из-за отсутствия байтов в диапазоне 80-FF.
UTF-8
Bom - это ef bb bf. Но вы не можете полагаться на это. Многие файлы UTF-8 не имеют отношения, особенно если они возникают в системах, не являющихся Windows.
Но вы можете с уверенностью предположить, что если файл проверяет как UTF-8, он является UTF-8. Ложные позитивы редки.
В частности, учитывая, что данные не являются ASCII, ложная положительная скорость для 2-байтовой последовательности составляет всего 3,9% (1920/49152). Для 7-байтовой последовательности это менее 1%. Для 12-байтовой последовательности это менее 0,1%. Для 24-байтовой последовательности это менее 1 на миллион.
UTF-16
Bom - это fe ff (for be) или ff fe (для Le). Обратите внимание, что BOM UTF-16LE находится в начале UTF-32LE BOM, поэтому сначала проверьте UTF-32.
Если у вас есть файл, который состоит в основном из символов ISO-8859-1, наличие половины байтов файла 00 также будет сильным показателем UTF-16.
В противном случае, единственный надежный способ распознавания UTF-16 без рода-найти суррогатные пары (D [8-B] XX D [CF] XX), но не BMP символы слишком редко используются, чтобы сделать этот подход практичным Анкет
XML
Если ваш файл начинается с байтов 3C 3F 78 6D 6C (т.е. символы ASCII " encoding=
декларация. Если присутствовать, то используйте это кодирование. Если отсутствовать, предположим, что UTF-8, который является кодированием XML по умолчанию.
Если вам нужно поддерживать EBCDIC, также ищите эквивалентную последовательность 4C 6F A7 94 93.
В общем, если у вас есть формат файла, который содержит объявление кодирования, то ищите это объявление, а не пытаться угадать кодирование.
Ни один из вышеперечисленных
Существуют сотни других средств, которые требуют больше усилий для обнаружения. Я рекомендую попробовать Детектор Charset Mozilla или же это порт .NET.
Разумный дефолт
Если вы исключили кодировки UTF и не имеете кодирующего объявления или статистического обнаружения, которое указывает на другое кодирование, предположим ISO-8859-1 или тесно связанный Windows-1252. Анкет (Обратите внимание, что последний стандарт HTML требует объявление «ISO-8859-1», которое будет интерпретировано как Windows-1252.) Кодовая страница Windows по умолчанию для английского языка (и других популярных языков, таких как испанский, португальский, немецкий и французский), это наиболее часто встречающиеся кодиры, кроме как кроме, кроме как UTF-8.
Другие советы
Если вы хотите получить «простое» решение, вы можете найти этот класс, я собрал полезным:
http://www.architectshack.com/textfileencodingdetector.ashx
Сначала он выполняет автоматическое обнаружение BOM, а затем пытается дифференцировать кодирования Unicode без BOM, по сравнению с некоторым другим кодированием по умолчанию (обычно Windows-1252, неправильно помеченный как кодирование. ASCII в .NET).
Как отмечалось выше, более сложное решение с участием Nchardet или Mlang может быть более уместным, и, как я отмечаю на странице обзора этого класса, лучше всего обеспечить некоторую форму интерактивности с пользователем, если это вообще, потому что просто есть просто невозможен на 100% обнаружение!
Использовать StreamReader
и направить его, чтобы обнаружить кодирование для вас:
using (var reader = new System.IO.StreamReader(path, true))
{
var currentEncoding = reader.CurrentEncoding;
}
И использовать Идентификаторы кодовой страницы https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspxЧтобы переключить логику в зависимости от этого.
Несколько ответов здесь, но никто не опубликовал полезный код.
Вот мой код, который обнаруживает все кодирования, которые Microsoft обнаруживает в Framework 4 в классе StreamReader.
Очевидно, что вы должны назвать эту функцию сразу после открытия потока, прежде чем читать что -либо еще из потока, потому что BOM являются первыми байтами в потоке.
Эта функция требует потока, который может искать (например, FileStream). Если у вас есть поток, который не может искать, вы должны написать более сложный код, который возвращает байтовый буфер с байтами, которые уже были прочитаны, но это не родилось.
/// <summary>
/// UTF8 : EF BB BF
/// UTF16 BE: FE FF
/// UTF16 LE: FF FE
/// UTF32 BE: 00 00 FE FF
/// UTF32 LE: FF FE 00 00
/// </summary>
public static Encoding DetectEncoding(Stream i_Stream)
{
if (!i_Stream.CanSeek || !i_Stream.CanRead)
throw new Exception("DetectEncoding() requires a seekable and readable Stream");
// Try to read 4 bytes. If the stream is shorter, less bytes will be read.
Byte[] u8_Buf = new Byte[4];
int s32_Count = i_Stream.Read(u8_Buf, 0, 4);
if (s32_Count >= 2)
{
if (u8_Buf[0] == 0xFE && u8_Buf[1] == 0xFF)
{
i_Stream.Position = 2;
return new UnicodeEncoding(true, true);
}
if (u8_Buf[0] == 0xFF && u8_Buf[1] == 0xFE)
{
if (s32_Count >= 4 && u8_Buf[2] == 0 && u8_Buf[3] == 0)
{
i_Stream.Position = 4;
return new UTF32Encoding(false, true);
}
else
{
i_Stream.Position = 2;
return new UnicodeEncoding(false, true);
}
}
if (s32_Count >= 3 && u8_Buf[0] == 0xEF && u8_Buf[1] == 0xBB && u8_Buf[2] == 0xBF)
{
i_Stream.Position = 3;
return Encoding.UTF8;
}
if (s32_Count >= 4 && u8_Buf[0] == 0 && u8_Buf[1] == 0 && u8_Buf[2] == 0xFE && u8_Buf[3] == 0xFF)
{
i_Stream.Position = 4;
return new UTF32Encoding(true, true);
}
}
i_Stream.Position = 0;
return Encoding.Default;
}
Вы должны прочитать это: Как я могу обнаружить кодировку/кодировку текстового файла
Если ваш файл начинается с байтов 60, 118, 56, 46 и 49, у вас есть неоднозначный случай. Это может быть UTF-8 (без BOM) или любые из одиночных байтовых кодировков, таких как ASCII, ANSI, ISO-8859-1 и т. Д.
я использую Ude Это порт C# Mozilla Universal Detector. Это прост в использовании и дает действительно хорошие результаты.