Вот моя ситуация: мне нужно правильно определить, какая кодировка символов используется для данного текстового файла. Надеюсь, он может правильно вернуть один из следующих типов:
enum CHARACTER_ENCODING
{
ANSI,
Unicode,
Unicode_big_endian,
UTF8_with_BOM,
UTF8_without_BOM
};
До сих пор я могу правильно определить текстовый файл как Unicode
, Unicode big endian
или UTF-8 with BOM
, вызвав следующую функцию. Он также может правильно определить для ANSI
, если данный текстовый файл изначально не является UTF-8 without BOM
. Проблема в том, что если текстовым файлом является UTF-8 without BOM
, следующая функция по ошибке считает его файлом ANSI
.
CHARACTER_ENCODING get_text_file_encoding(const char *filename)
{
CHARACTER_ENCODING encoding;
unsigned char uniTxt[] = {0xFF, 0xFE};// Unicode file header
unsigned char endianTxt[] = {0xFE, 0xFF};// Unicode big endian file header
unsigned char utf8Txt[] = {0xEF, 0xBB};// UTF_8 file header
DWORD dwBytesRead = 0;
HANDLE hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
hFile = NULL;
CloseHandle(hFile);
throw runtime_error("cannot open file");
}
BYTE *lpHeader = new BYTE[2];
ReadFile(hFile, lpHeader, 2, &dwBytesRead, NULL);
CloseHandle(hFile);
if (lpHeader[0] == uniTxt[0] && lpHeader[1] == uniTxt[1])// Unicode file
encoding = CHARACTER_ENCODING::Unicode;
else if (lpHeader[0] == endianTxt[0] && lpHeader[1] == endianTxt[1])// Unicode big endian file
encoding = CHARACTER_ENCODING::Unicode_big_endian;
else if (lpHeader[0] == utf8Txt[0] && lpHeader[1] == utf8Txt[1])// UTF-8 file
encoding = CHARACTER_ENCODING::UTF8_with_BOM;
else
encoding = CHARACTER_ENCODING::ANSI; //Ascii
delete []lpHeader;
return encoding;
}
Эта проблема меня давно блокирует, и я до сих пор не могу найти хорошее решение. Любой намек будет оценен по достоинству.
1 ответ
Во-первых, нет такой физической кодировки, как «Юникод». Вы, вероятно, имеете в виду UTF-16. Во-вторых, любой файл допустим в "ANSI" или любой однобайтовой кодировке, если на то пошло. Единственное, что вы можете сделать, - это угадать в наилучшем порядке, который с наибольшей вероятностью выбрасывает недопустимые совпадения.
Вы должны проверить в следующем порядке:
- Есть ли в начале спецификация UTF-16? Тогда это, наверное, UTF-16. Используйте спецификацию в качестве индикатора, является ли она прямым или прямым порядком байтов, а затем проверьте остальную часть файла, соответствует ли она.
- Есть ли в начале спецификация UTF-8? Тогда это, наверное, UTF-8. Проверьте остальную часть файла.
- Если вышеуказанное не привело к положительному совпадению, проверьте, соответствует ли весь файл UTF-8. Если это так, вероятно, это UTF-8.
- Если вышеуказанное не привело к положительному совпадению, вероятно, это ANSI.
Если вы ожидаете, что файлы UTF-16 без спецификации также будут (это возможно, например, для файлов XML, которые указывают кодировку в объявлении XML), то вам также необходимо вставить это правило туда. Хотя любое из вышеперечисленного может привести к ложному срабатыванию, ошибочно идентифицируя файл ANSI как UTF- * (хотя это маловероятно ). У вас всегда должны быть метаданные , которые сообщают вам, в какой кодировке находится файл, обнаружение их постфактум невозможно со 100% точностью.
UTF-16
. Вместо этого у него есть еще два типа: UCS-2 Big Endian
и UCS-2 Little Endian
. Итак, UTF-16
здесь эквивалентен UCS-2
?
Похожие вопросы
Связанные вопросы
Новые вопросы
c++
C ++ - это язык программирования общего назначения. Первоначально он был разработан как расширение C и имеет аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде (который должен быть) скомпилирован с помощью компилятора C ++. Используйте тег для конкретной версии для вопросов, связанных с конкретной версией стандарта [C ++ 11], [C ++ 14], [C ++ 17], [C ++ 20] или [C ++ 23] и т. Д. .
enum
.