В спецификации W3C XML есть раздел о том, как определить кодировку байтовой строки.
Первая проверка на метку порядка байтов Unicode
Спецификация - это просто другой персонаж; это:
'НУЛЬ ПЕРЕКЛЮЧЕНИЯ С НУЛЕМ' (U + FEFF)
Символ U + FEFF вместе со всеми другими символами в файле кодируется с использованием соответствующей схемы кодирования:
00 00 FE FF
: UCS-4, машина с прямым порядком байтов (порядок 1234)
FF FE 00 00
: UCS-4, машина с прямым порядком байтов (порядок 4321)
00 00 FF FE
: UCS-4, необычный порядок октетов (2143)
FE FF 00 00
: UCS-4, необычный порядок октетов (3412)
FE FF ## ##
: UTF-16, big-endian
FF FE ## ##
: UTF-16, little-endian
EF BB BF
: UTF-8
, где ## ##
может быть чем угодно - за исключением того, что оба равны нулю
Итак, сначала проверьте начальные байты для любой из этих подписей. Если вы найдете один из них, верните этот идентификатор кодовой страницы
UInt32 GuessEncoding(byte[] XmlString)
{
if BytesEqual(XmlString, [00, 00, $fe, $ff]) return 12001; //"utf-32BE" - Unicode UTF-32, big endian byte order
if BytesEqual(XmlString, [$ff, $fe, 00, 00]) return 1200; //"utf-32" - Unicode UTF-32, little endian byte order
if BytesEqual(XmlString, [$fe, $ff, 00, 00]) throw new Exception("Nobody supports 2143 UCS-4");
if BytesEqual(XmlString, [$fe, $ff, 00, 00]) throw new Exception("Nobody supports 3412 UCS-4");
if BytesEqual(XmlString, [$fe, $ff])
{
if (XmlString[2] <> 0) && (XmlString[3] <> 0)
return 1201; //"unicodeFFFE" - Unicode UTF-16, big endian byte order
}
if BytesEqual(XmlString, [$ff, $fe])
{
if (XmlString[2] <> 0) && (XmlString[3] <> 0)
return 1200; //"utf-16" - Unicode UTF-16, little endian byte order
}
if BytesEqual(XmlString, [$ef, $bb, $bf]) return 65001; //"utf-8" - Unicode (UTF-8)
Или поищите <? Xml </h2>
Если документ XML не имеет символа метки байтового порядка, вы переходите к поиску первых пяти символов, которые должен иметь каждый документ XML:
<?xml
Полезно знать, что
<
is # x0000003C
?
is # x0000003F
С этого нам достаточно взглянуть на первые четыре байта:
00 00 00 3C
: UCS-4, машина с прямым порядком байтов (порядок 1234)
3C 00 00 00
: UCS-4, машина с прямым порядком байтов (порядок 4321)
00 00 3C 00
: UCS-4, необычный порядок октетов (2143)
00 3C 00 00
: UCS-4, необычный порядок октетов (3412)
00 3C 00 3F
: UTF-16, big-endian
3C 00 3F 00
: UTF-16, little-endian
3C 3F 78 6D
: UTF-8
4C 6F A7 94
: немного вкуса EBCDIC
Итак, мы можем добавить больше к нашему коду:
if BytesEqual(XmlString, [00, 00, 00, $3C]) return 12001; //"utf-32BE" - Unicode UTF-32, big endian byte order
if BytesEqual(XmlString, [$3C, 00, 00, 00]) return 1200; //"utf-32" - Unicode UTF-32, little endian byte order
if BytesEqual(XmlString, [00, 00, $3C, 00]) throw new Exception("Nobody supports 2143 UCS-4");
if BytesEqual(XmlString, [00, $3C, 00, 00]) throw new Exception("Nobody supports 3412 UCS-4");
if BytesEqual(XmlString, [00, $3C, 00, $3F]) return return 1201; //"unicodeFFFE" - Unicode UTF-16, big endian byte order
if BytesEqual(XmlString, [$3C, 00, $3F, 00]) return 1200; //"utf-16" - Unicode UTF-16, little endian byte order
if BytesEqual(XmlString, [$3C, $3F, $78, $6D]) return 65001; //"utf-8" - Unicode (UTF-8)
if BytesEqual(XmlString, [$4C, $6F, $A7, $94])
{
//Some variant of EBCDIC, e.g.:
//20273 IBM273 IBM EBCDIC Germany
//20277 IBM277 IBM EBCDIC Denmark-Norway
//20278 IBM278 IBM EBCDIC Finland-Sweden
//20280 IBM280 IBM EBCDIC Italy
//20284 IBM284 IBM EBCDIC Latin America-Spain
//20285 IBM285 IBM EBCDIC United Kingdom
//20290 IBM290 IBM EBCDIC Japanese Katakana Extended
//20297 IBM297 IBM EBCDIC France
//20420 IBM420 IBM EBCDIC Arabic
//20423 IBM423 IBM EBCDIC Greek
//20424 IBM424 IBM EBCDIC Hebrew
//20833 x-EBCDIC-KoreanExtended IBM EBCDIC Korean Extended
//20838 IBM-Thai IBM EBCDIC Thai
//20866 koi8-r Russian (KOI8-R); Cyrillic (KOI8-R)
//20871 IBM871 IBM EBCDIC Icelandic
//20880 IBM880 IBM EBCDIC Cyrillic Russian
//20905 IBM905 IBM EBCDIC Turkish
//20924 IBM00924 IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)
throw new Exception("We don't support EBCDIC. Sorry");
}
//Otherwise assume UTF-8, and fail to decode it anyway
return 65001; //"utf-8" - Unicode (UTF-8)
//Any code is in the public domain. No attribution required.
}