Разница между UTF-8 и UTF-16?


137

Разница между UTF-8 и UTF-16? Зачем нам это нужно?

MessageDigest md = MessageDigest.getInstance("SHA-256");
String text = "This is some text";

md.update(text.getBytes("UTF-8")); // Change this to "UTF-16" if needed
byte[] digest = md.digest();

2
У Джона Скита есть хорошая статья о кодировании .... csharpindepth.com/Articles/General/Unicode.aspx
Митч Пшеничный

Ответы:


284

Я считаю, что в Интернете есть много хороших статей на эту тему, но вот краткое резюме.

И UTF-8, и UTF-16 являются кодировками переменной длины. Однако в UTF-8 символ может занимать минимум 8 битов, тогда как в UTF-16 длина символа начинается с 16 битов.

Основные плюсы UTF-8:

  • Основные символы ASCII, такие как цифры, латинские символы без акцентов и т. Д., Занимают один байт, который идентичен представлению US-ASCII. Таким образом, все строки US-ASCII становятся действительными UTF-8, что обеспечивает приличную обратную совместимость во многих случаях.
  • Нет нулевых байтов, что позволяет использовать строки с нулевым символом в конце, что также обеспечивает большую обратную совместимость.
  • UTF-8 не зависит от порядка байтов, поэтому вам не нужно беспокоиться о проблеме Big Endian / Little Endian.

Основные минусы UTF-8:

  • Многие обычные символы имеют разную длину, что замедляет индексацию по кодам и ужасно вычисляет количество кодов.
  • Даже если порядок байтов не имеет значения, иногда в UTF-8 все еще имеется спецификация (метка порядка байтов), которая служит для уведомления о том, что текст кодируется в UTF-8, а также нарушает совместимость с программным обеспечением ASCII, даже если текст содержит только символы ASCII. , Программное обеспечение Microsoft (например, Блокнот) особенно любит добавлять спецификации в UTF-8.

Основные плюсы UTF-16:

  • Символы BMP (базовая многоязычная плоскость), включая латиницу, кириллицу, большинство китайских языков (КНР сделала поддержку некоторых кодовых точек вне BMP обязательной), большинство японских языков могут быть представлены 2 байтами. Это ускоряет индексирование и подсчет количества кодовых точек в случае, если текст не содержит дополнительных символов.
  • Даже если текст содержит дополнительные символы, они все равно представлены парами 16-битных значений, что означает, что общая длина все еще делится на два и позволяет использовать 16-битный charв качестве примитивного компонента строки.

Основные минусы UTF-16:

  • Много нулевых байтов в строках US-ASCII, что означает отсутствие строк с нулевым символом в конце и много потерянной памяти.
  • Использование его в качестве кодировки фиксированной длины «в основном работает» во многих распространенных сценариях (особенно в США / ЕС / странах с кириллицей / Израилем / арабскими странами / Ираном и многими другими), что часто приводит к прерывистой поддержке, где это не так. Это означает, что программисты должны знать о суррогатных парах и правильно обращаться с ними в тех случаях, когда это важно!
  • Это переменная длина, поэтому подсчет или индексирование кодовых точек обходятся дорого, хотя и меньше, чем UTF-8.

В общем, UTF-16 обычно лучше для представления в памяти, потому что BE / LE там не имеет значения (просто используйте собственный порядок), а индексирование выполняется быстрее (просто не забудьте правильно обрабатывать суррогатные пары). UTF-8, с другой стороны, чрезвычайно хорош для текстовых файлов и сетевых протоколов, поскольку здесь нет проблемы BE / LE, а также часто бывает полезно нулевое завершение, а также ASCII-совместимость.


3
Отсутствует только часть BE / LE на UTF16 :) У UTF-8 есть еще один недостаток, он может генерировать более продолжительный выход, чем UTF16
bestsss

4
Да, я забыл про BE / LE. Это не имеет большого значения, особенно для использования в памяти. UTF-8 будет генерировать более длинный вывод, только если задействованы трехбайтовые символы, но это в основном означает китайский и японский языки. С другой стороны, если текст содержит много символов US-ASCII, он может генерировать более короткий вывод, поэтому, является ли это недостатком или нет, зависит от конкретной ситуации.
Сергей Таченов

Я даже не думал упомянуть непосредственного профессионала о UTF-8, более короткой длины. Что касается более длинного вывода utf-8, то это было «возможно» по какой-то причине, но если цель находится далеко на востоке, кодировка по умолчанию должна быть utf-16. Что касается примера md.update (text.getBytes ("UTF-8")); кодировка не имеет значения, поскольку хеш является стабильным в обоих направлениях.
bestsss

Самый быстрый способ конвертировать String в байтовый массив - это что-то вроде этого, записанное в качестве примера
bestsss

Вы говорите, что символы имеют разную длину в UTF-8, поэтому это замедляет индексирование и вычисление длины, но я сомневаюсь, что символы в UTF-16 тоже имеют разную длину, должны ли индексирование и вычисление длины UTF-16 быть быстрее?
nicky_zs

19

Это просто разные схемы для представления символов Unicode.

Оба имеют переменную длину - UTF-16 использует 2 байта для всех символов в основной многоязычной плоскости (BMP), которая содержит большинство символов общего пользования.

UTF-8 использует от 1 до 3 байтов для символов в BMP, до 4 для символов в текущем диапазоне Unicode от U + 0000 до U + 1FFFFF и расширяется до U + 7FFFFFFF, если это когда-либо становится необходимым ... но особенно все символы ASCII представлены одним байтом каждый.

Для целей дайджеста сообщений не имеет значения, какой из них вы выберете, если каждый, кто пытается воссоздать дайджест, использует одну и ту же опцию.

Смотрите эту страницу для получения дополнительной информации о UTF-8 и Unicode.

(Обратите внимание, что все символы Java являются кодовыми точками UTF-16 в BMP; для представления символов выше U + FFFF необходимо использовать суррогатные пары в Java.)


5

Безопасность: используйте только UTF-8

Разница между UTF-8 и UTF-16? Зачем нам это нужно?

В реализациях UTF-16 было как минимум несколько уязвимостей безопасности . Смотрите Википедию для деталей .

WHATWG и W3C уже в настоящее время объявили , что только UTF-8 будет использоваться в Интернете.

Описанные здесь проблемы [безопасности] исчезают, когда используется исключительно UTF-8, что является одной из многих причин, по которым теперь применяется обязательное кодирование для всех вещей.

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

Таким образом, хотя UTF-16 может продолжать использоваться внутри некоторых систем, таких как Java и Windows, то малое использование UTF-16, которое вы, возможно, видели в прошлом для файлов данных, обмена данными и т. Д., Вероятно, полностью исчезнет.


4

Это не связано с UTF-8/16 (в общем, хотя оно и преобразуется в UTF16, а часть BE / LE может быть установлена ​​с одной строкой), но ниже приведен самый быстрый способ преобразования строки в байт []. Например: хорошо подходит для указанного случая (хэш-код). String.getBytes (enc) относительно медленный.

static byte[] toBytes(String s){
        byte[] b=new byte[s.length()*2];
        ByteBuffer.wrap(b).asCharBuffer().put(s);
        return b;
    }

-3

Простой способ различить UTF-8 и UTF-16 состоит в том, чтобы определить общие черты между ними.

За исключением совместного использования одного и того же номера Unicode для данного символа, каждый из них имеет свой собственный формат.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.