Совместим ли 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/

Другие вопросы по тегам