Совместим ли UTF-16 с UTF-8?
Я задал Google вопрос выше и был отправлен Разница между UTF-8 и UTF-16? который, к сожалению, не отвечает на вопрос.
Насколько я понимаю, UTF-8 должен быть подмножеством значения UTF-16: если мой код использует UTF-16 и я передаю строку в кодировке UTF-8, все всегда должно быть в порядке. Обратный путь (ожидание UTF-8 и получение UTF-16) может вызвать проблемы.
Это верно?
РЕДАКТИРОВАТЬ: Чтобы уточнить, почему связанный вопрос SO не отвечает на мой вопрос: моя проблема возникла при попытке обработать строку JSON с помощью WebClient.DownloadString
потому что WebClient использовал неправильную кодировку. JSON, который я получил из запроса, был закодирован как UTF-8, и вопрос для меня был таков: webClient.Encoding = New System.Text.UnicodeEncoding
(иначе UTF-16) был бы я в безопасности, то есть мог бы обрабатывать результаты запроса UTF-8 и UTF-16, или я должен использовать webClient.Encoding = New System.Text.UTF8Encoding
?
1 ответ
Непонятно, что вы подразумеваете под "совместимостью", поэтому давайте разберемся с некоторыми основами.
Unicode является базовой концепцией, и должным образом реализованная UTF-16 и UTF-8 представляют собой два разных способа кодирования Unicode. Они, очевидно, разные - в противном случае, почему существуют два разных понятия?
Unicode сам по себе не определяет формат сериализации. UTF-8 и UTF-16 - два альтернативных формата сериализации.
Они "совместимы" в том смысле, что они могут представлять одни и те же кодовые точки Unicode, но "несовместимы" в том смысле, что представления совершенно разные.
Есть два дополнительных поворота с UTF-16. На самом деле есть две разные кодировки, UTF-16LE и UTF-16BE. Они отличаются порядком байтов. (UTF-8 является байтовой кодировкой, поэтому не имеет порядкового номера.) Раньше прежний UTF-16 ограничивался 65 536 возможными символами, что меньше, чем в настоящее время содержит Unicode. Это обрабатывается суррогатами, но действительно старые и / или неработающие реализации UTF-16 (правильно обозначенные как UCS-2, а не "настоящий" UTF-16) не поддерживают их.
Для большей конкретности давайте сравним четыре разных кода. Мы выбираем U + 0041, U+00E5, U + 201C и U + 1F4A9, так как они хорошо иллюстрируют различия.
U + 0041 является 7-битным символом, поэтому UTF-8 представляет его просто одним байтом. U+00E5 является 8-битным символом, поэтому UTF-8 должен его кодировать. U+1F4A9 находится вне Базовой многоязычной плоскости, поэтому UTF-16 представляет его в суррогатной последовательности. Наконец, U+201C не является ни одним из вышеперечисленных.
Вот изображения наших кандидатов в символы UTF-8, UTF-16LE и UTF-16BE.
Character | UTF-8 | UTF-16LE | UTF-16BE |
----------+---------------------+---------------------+---------------------+
U+0041 | 0x41 | 0x41 0x00 | 0x00 0x41 |
U+00E5 | 0xC3 0xA5 | 0xE5 0x00 | 0x00 0xE5 |
U+201C | 0xE2 0x80 0x9C | 0x1C 0x20 | 0x20 0x1C |
U+1F4A9 | 0xF0 0x9F 0x92 0xA9 | 0x3D 0xD8 0xA9 0xDC | 0xD8 0x3D 0xDC 0xA9 |
Чтобы выбрать один очевидный пример, кодировка UTF-8 U+00E5 будет представлять совершенно другой символ, если интерпретировать его как UTF-16 (в UTF-16LE это будет U + A5C3, а в UTF-16BE - U + C3A5. Наоборот, многие из кодов UTF-16 вообще не являются действительными последовательностями UTF-8. Таким образом, в этом смысле UTF-8 и UTF-16 полностью и совершенно несовместимы.
В современных языках программирования ваш код должен просто использовать Unicode и позволить языку легко обрабатывать его кодирование так, чтобы он подходил для вашей платформы и библиотек. Относительно тангенциальной ноты см. Также http://utf8everywhere.org/