Різниця між 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
jon skeet має хорошу статтю про кодування .... 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 все ще має BOM (позначку порядку в байтах), яка служить для повідомлення про те, що текст кодується в UTF-8, а також порушує сумісність з програмним забезпеченням ASCII, навіть якщо текст містить лише символи ASCII . Програмне забезпечення Microsoft (наприклад, Блокнот) особливо любить додавати BOM до UTF-8.

Основні плюси UTF-16:

  • Символи BMP (основна багатомовна площина), включаючи латинську, кириличну, більшість китайських (КНР зробила підтримку деяких точок коду поза BMP обов'язковою), більшість японців можуть бути представлені двома байтами. Це прискорює індексацію та обчислення кількості кодових точок, якщо текст не містить додаткових символів.
  • Навіть якщо в тексті є додаткові символи, вони все ще представлені парами 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 в байт []. Наприклад: добре точно для наданого випадку (хеш-код). String.getBytes (enc) відбувається досить повільно.

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

-2

Простий спосіб диференціювати UTF-8 і UTF-16 - це визначити спільність між ними.

Крім спільного використання одного і того ж номера унікоду для заданого символу, кожен має свій власний формат.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.