Что такое Юникод, UTF-8, UTF-16?

395

Что является основой для Unicode и зачем нужен UTF-8 или UTF-16? Я исследовал это в Google и искал здесь, но мне это не ясно.

В VSS при сравнении файлов иногда появляется сообщение о том, что два файла имеют разные UTF. Почему это так?

Пожалуйста, объясните в простых терминах.

SoftwareGeek
источник
123
Похоже, вам нужно прочитать Абсолютный минимум, который должен знать каждый разработчик программного обеспечения. Абсолютно, необходимо знать о Unicode и наборах символов ! Это очень хорошее объяснение того, что происходит.
Брайан Агнью
5
Этот FAQ с официального сайта Unicode имеет несколько ответов для вас.
Неманя Трифунович
4
@John: это очень хорошее введение, но это не окончательный источник: он пропускает довольно много деталей (что хорошо для обзора / введения!)
Йоахим Зауэр
5
Статья отличная, но в ней есть несколько ошибок, и она представляет UTF-8 в несколько консервативном свете. Я предлагаю читать utf8everywhere.org в качестве дополнения.
Павел Радзивиловский
2
Взгляните на этот сайт: utf8everywhere.org
Vertexwahn

Ответы:

551

Зачем нам нужен Юникод?

В (не слишком) первые дни все, что существовало, было ASCII. Это было хорошо, так как все, что когда-либо понадобилось, это несколько контрольных символов, знаки препинания, цифры и буквы, подобные тем, которые указаны в этом предложении. К сожалению, сегодняшний странный мир глобального общения и социальных сетей не предвиделся, и нередко видеть английский, английский, английский, английский и французский в том же документе (надеюсь, я не сломал старые браузеры).

Но ради аргумента, допустим, Джо Средний разработчик программного обеспечения. Он настаивает на том, что ему когда-либо понадобится только английский, и поэтому он хочет использовать только ASCII. Это может быть хорошо для пользователя Джо , но это не хорошо для разработчика программного обеспечения Джо . Приблизительно половина мира использует нелатинские символы, и использование ASCII для этих людей, возможно, неуместно, и, кроме того, он закрывает свое программное обеспечение для большой и растущей экономики.

Поэтому необходим всеобъемлющий набор символов, включающий все языки. Так появился Unicode. Каждому символу присваивается уникальный номер, называемый кодовой точкой . Одно из преимуществ Unicode над другими возможными наборами состоит в том, что первые 256 кодовых точек идентичны ISO-8859-1. и, следовательно, также ASCII. Кроме того, подавляющее большинство обычно используемых символов представлено только двумя байтами в области, называемой базовой многоязычной плоскостью (BMP) . Теперь для доступа к этому набору символов требуется кодировка символов, и, как задается вопрос, я сосредоточусь на UTF-8 и UTF-16.

Соображения памяти

Так сколько байтов дают доступ к каким символам в этих кодировках?

  • UTF-8:
    • 1 байт: стандарт ASCII
    • 2 байта: арабский, иврит, большинство европейских шрифтов (особенно исключая грузинский) )
    • 3 байта: BMP
    • 4 байта: все символы Unicode
  • UTF-16:
    • 2 байта: BMP
    • 4 байта: все символы Unicode

Теперь стоит упомянуть, что символы, отсутствующие в BMP, включают древние сценарии, математические символы, музыкальные символы и более редкие символы китайского / японского / корейского языков (CJK) .

Если вы будете работать в основном с символами ASCII, то UTF-8, безусловно, более эффективно использует память. Однако, если вы работаете в основном с неевропейскими сценариями, использование UTF-8 может потреблять до 1,5 раз меньше памяти, чем UTF-16. При работе с большими объемами текста, такими как большие веб-страницы или длинные текстовые документы, это может повлиять на производительность.

Основы кодирования

Примечание. Если вы знаете, как кодируются UTF-8 и UTF-16, перейдите к следующему разделу для практического применения.

  • UTF-8: для стандартных символов ASCII (0-127) коды UTF-8 идентичны. Это делает UTF-8 идеальным, если требуется обратная совместимость с существующим текстом ASCII. Другие символы требуют от 2-4 байтов. Это делается путем резервирования некоторых битов в каждом из этих байтов, чтобы указать, что он является частью многобайтового символа. В частности, первый бит каждого байта 1должен избегать конфликтов с символами ASCII.
  • UTF-16: для допустимых символов BMP представление UTF-16 является просто его кодовой точкой. Однако для не-BMP символов UTF-16 вводит суррогатные пары . В этом случае комбинация двух двухбайтовых частей отображается на не-BMP символ. Эти двухбайтовые части взяты из числового диапазона BMP, но гарантируются стандартом Unicode как недопустимые символы BMP. Кроме того, поскольку UTF-16 имеет два байта в качестве базовой единицы, на него влияет порядок байтов . Чтобы компенсировать это, зарезервированная метка порядка байтов может быть размещена в начале потока данных, который указывает порядковый номер. Таким образом, если вы читаете ввод UTF-16, и не указан порядковый номер, вы должны проверить это.

Как видно, UTF-8 и UTF-16 далеко не совместимы друг с другом. Поэтому, если вы делаете ввод / вывод, убедитесь, что вы знаете, какую кодировку вы используете! Для получения более подробной информации об этих кодировках, пожалуйста, смотрите UTF FAQ .

Практические вопросы программирования

Символьные и строковые типы данных: как они кодируются на языке программирования? Если они являются необработанными байтами, в ту минуту, когда вы попытаетесь вывести символы, отличные от ASCII, вы можете столкнуться с несколькими проблемами. Кроме того, даже если тип символа основан на UTF, это не означает, что строки являются правильными UTF. Они могут разрешать байтовые последовательности, которые являются недопустимыми. Как правило, вам придется использовать библиотеку, которая поддерживает UTF, такую ​​как ICU для C, C ++ и Java. В любом случае, если вы хотите ввести / вывести что-то отличное от кодировки по умолчанию, вам придется сначала преобразовать это.

Рекомендуемые / стандартные / доминантные кодировки: при выборе UTF, как правило, лучше всего следовать рекомендуемым стандартам для среды, в которой вы работаете. Например, UTF-8 является доминирующим в Интернете, а с HTML5 он была рекомендована кодировка . И наоборот, среды .NET и Java основаны на символьном типе UTF-16. Смущает (и неправильно), ссылки часто делаются на «кодировку Unicode», которая обычно относится к доминирующей кодировке UTF в данной среде.

Поддержка библиотек: используемые вами библиотеки поддерживают некоторую кодировку. Который из? Они поддерживают угловые дела? Поскольку необходимость является матерью изобретения, библиотеки UTF-8 обычно поддерживают должным образом 4-байтовые символы, поскольку часто могут встречаться 1, 2 и даже 3 байта. Однако не все предполагаемые библиотеки UTF-16 поддерживают суррогатные пары должным образом, поскольку они встречаются очень редко.

Подсчет символов: в Юникоде есть комбинируемые символы. Например, кодовая точка U + 006E (n) и U + 0303 (комбинированная тильда) образуют -, но кодовая точка U + 00F1 образует -. Они должны выглядеть одинаково, но простой алгоритм подсчета вернет 2 для первого примера, 1 для последнего. Это не обязательно неправильно, но может и не быть желаемым результатом.

Сравнение на равенство: A, А и Α выглядят одинаково, но они латинские, кириллические и греческие соответственно. У вас также есть такие случаи, как C и Ⅽ, один - буква, другой - римская цифра. Кроме того, у нас есть комбинации символов, которые необходимо учитывать. Для получения дополнительной информации см. Повторяющиеся символы в Юникоде .

Суррогатные пары: они встречаются достаточно часто на SO, поэтому я просто приведу несколько примеров ссылок:

Другие ?:

DPenner1
источник
11
Отличный ответ, большие шансы на награду ;-) Лично я бы добавил, что некоторые утверждают, что UTF-8 является универсальной кодировкой символов , но я знаю, что это мнение не обязательно разделяют все.
Йоахим Зауэр
3
Все еще слишком технически для меня на данном этапе. Как слово hello хранится в компьютере в UTF-8 и UTF-16?
Фамилия Фамилия
1
Не могли бы вы подробнее рассказать, почему, например, BMP занимает 3 байта в UTF-8? Я бы подумал, что, поскольку его максимальное значение 0xFFFF (16 бит), то для доступа к нему потребуется всего 2 байта.
отметка
2
@mark Некоторые биты зарезервированы для целей кодирования. Для кодовой точки, которая занимает 2 байта в UTF-8, есть 5 зарезервированных битов, оставляя только 11 битов для выбора кодовой точки. U + 07FF заканчивается самой высокой кодовой точкой, представляемой в 2 байтах.
DPenner1
1
КСТАТИ - ASCII определяет только 128 кодовых точек, используя только 7 бит для представления. Это ISO-8859-1 / ISO-8859-15, которые определяют 256 кодовых точек и используют 8 бит для представления. Первые 128 кодовых точек во всех этих 3 одинаковы.
Tuxdude
68
  • Unicode
    • это набор символов, используемых по всему миру
  • UTF-8,
    • кодировка символов, способная кодировать все возможные символы (называемые кодовыми точками) в Unicode.
    • кодовая единица - 8 бит
    • использовать от одного до четырех единиц кода для кодирования Unicode
    • 00100100 для " $ " (один 8- битный ); 11000010 10100010 для « ¢ » (два 8-битных); 11100010 10000010 10101100 для " " (три 8- битных )
  • UTF-16
    • другая кодировка символов
    • кодовая единица - 16 бит
    • используйте одну-две единицы кода для кодирования Unicode
    • 00000000 00100100 для " $ " (один 16- битный ); 11011000 01010010 11011111 01100010 для " 𤭢 " (два 16- битных )
wengeezhang
источник
1
Коротко и точно
Аритра Чаттерджи
30

Юникод - довольно сложный стандарт. Не бойтесь слишком сильно, но будьте готовы к какой-то работе! [2]

Поскольку заслуживающий доверия ресурс всегда нужен, но официальный отчет огромен, я предлагаю прочитать следующее:

  1. Абсолютный минимум Каждый разработчик программного обеспечения Абсолютно, положительно должен знать о Юникоде и наборах символов (никаких оправданий!) Введение Джоэл Спольски, генеральный директор Stack Exchange.
  2. Для БМП и не только! Учебник Эрика Мюллера, технического директора, а затем вице-президента консорциума Unicode. (первые 20 слайдов и все готово)

Краткое объяснение:

Компьютеры читают байты, а люди читают символы, поэтому мы используем стандарты кодирования для сопоставления символов с байтами. ASCII был первым широко используемым стандартом, но охватывает только латиницу (7 бит / символ может представлять 128 различных символов). Unicode - это стандарт, цель которого - охватить все возможные символы в мире (может содержать до 1114 112 символов, то есть максимум 21 бит / символ. В настоящее время Unicode 8.0 содержит 120 737 символов, и все).

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

Каждый символ занимает перечисляемую позицию от 0 до 1 114 111 (hex: 0-10FFFF), называемую кодовой точкой . Кодирующая форма отображает точку кода в код блока последовательности. Блок кода является способ , которым Вы хотите символы , которые будут организованы в памяти, 8-битных, 16-битных блоков и так далее. UTF-8 использует от 1 до 4 блоков по 8 битов, а UTF-16 использует 1 или 2 блока по 16 битов, чтобы охватить весь Unicode максимум из 21 бита. Единицы используют префиксы, чтобы можно было определить границы символов, и чем больше единиц, тем больше префиксов занимают биты. Таким образом, хотя UTF-8 использует 1 байт для латинского алфавита, ему требуется 3 байта для более поздних сценариев внутри базовой многоязычной плоскости, в то время как UTF-16 использует 2 байта для всех этих. И это их главное отличие. Наконец,

схема кодирования (например, UTF-16BE или UTF-16LE) отображает (сериализует) последовательность единиц кода в последовательность байтов.

символ: π
кодовая точка: U + 03C0
формы кодирования (кодовые единицы):
      UTF-8: CF 80
      UTF-16: 03C0
схемы кодирования (байты):
      UTF-8: CF 80
      UTF-16BE: 03 C0
      UTF-16LE: C0 03

Совет: шестнадцатеричная цифра представляет 4 бита, поэтому шестнадцатеричное число, состоящее из двух цифр, представляет байт.
Также посмотрите на карты самолетов в Википедии, чтобы получить представление о расположении набора символов.

нейрон
источник
19

Изначально Unicode должен был иметь 16-битное кодирование с фиксированной шириной (UCS-2). Первые пользователи Unicode, такие как Java и Windows NT, создавали свои библиотеки вокруг 16-битных строк.

Позже область действия Unicode была расширена и теперь включает в себя исторические символы, для чего потребуется более 65 536 кодовых точек, которые будет поддерживать 16-битное кодирование. Чтобы допустить представление дополнительных символов на платформах, которые использовали UCS-2, была введена кодировка UTF-16. Он использует «суррогатные пары» для представления символов в дополнительных плоскостях.

Между тем, многие старые программы и сетевые протоколы использовали 8-битные строки. UTF-8 был создан, чтобы эти системы могли поддерживать Unicode без использования широких символов. Он обратно совместим с 7-битным ASCII.

dan04
источник
3
Стоит отметить, что Microsoft по- прежнему называет UTF-16 Unicode, что добавляет путаницы. Два не одинаковы.
Марк Рэнсом
16

Эта статья объясняет все детали http://kunststube.net/encoding/

ПИСЬМО В БУФЕР

если вы записываете в 4-байтовый буфер, символ с кодировкой UTF8, ваш двоичный файл будет выглядеть так:

00000000 11100011 10000001 10000010

если вы записываете в 4-байтовый буфер, символ с кодировкой UTF16, ваш двоичный файл будет выглядеть так:

00000000 00000000 00110000 01000010

Как вы можете видеть, в зависимости от того, какой язык вы будете использовать в своем контенте, это соответственно повлияет на вашу память.

Например, для этого конкретного символа: кодировка UTF16 более эффективна, поскольку у нас есть 2 свободных байта для следующего символа. Но это не значит, что вы должны использовать UTF16 для японского алфавита.

ЧТЕНИЕ ИЗ БУФЕРА

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

Например, если вы расшифруете это: 00000000 11100011 10000001 10000010 в кодировку UTF16, вы получите не

Примечание. Кодировка и Unicode - это две разные вещи. Unicode - это большой (таблица) с каждым символом, сопоставленным с уникальной кодовой точкой. Например, символ (буква) имеет (кодовую точку) : 30 42 (шестнадцатеричное). Кодирование, с другой стороны, представляет собой алгоритм, который преобразует символы более подходящим способом при хранении на аппаратном уровне.

30 42 (hex) - > UTF8 encoding - > E3 81 82 (hex), which is above result in binary.

30 42 (hex) - > UTF16 encoding - > 30 42 (hex), which is above result in binary.

введите описание изображения здесь

InGeek
источник
12

Unicode - это стандарт, который отображает символы на всех языках в определенное числовое значение, называемое Code Points . Причиной этого является то, что он позволяет использовать разные кодировки с использованием одного и того же набора кодовых точек.

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

Выбор конкретной кодировки зависит от ваших требований. Разные кодировки имеют разные требования к памяти, и в зависимости от символов, с которыми вы будете иметь дело, вы должны выбрать кодировку, которая использует наименьшую последовательность байтов для кодирования этих символов.

Для более подробной информации о Unicode, UTF-8 и UTF-16, вы можете проверить эту статью,

Что каждый программист должен знать о Unicode

Кишу Агарвал
источник
9

Почему юникод? Потому что в ASCII всего 127 символов. Те от 128 до 255 отличаются в разных странах, поэтому есть кодовые страницы. Поэтому они сказали, что пусть до 1114111 символов. Итак, как вы храните самую высокую кодовую точку? Вам нужно будет хранить его с использованием 21 бита, поэтому вы будете использовать DWORD, имеющий 32 бита и потраченные 11 битов. Поэтому, если вы используете DWORD для хранения символа Юникода, это самый простой способ, потому что значение в вашем DWORD точно соответствует кодовой точке. Но массивы DWORD, конечно, больше, чем массивы WORD, и, конечно, даже больше, чем массивы BYTE. Вот почему существует не только UTF-32, но и UTF-16. Но utf-16 означает поток WORD, а WORD имеет 16 битов, так как же самая высокая кодовая точка 1114111 может вписаться в WORD? Оно не может! Поэтому они помещают все, что выше 65535, в DWORD, который они называют суррогатной парой. Такая суррогатная пара - это два слова, и их можно обнаружить, посмотрев на первые 6 бит. Так что насчет utf-8? Это байтовый массив или байтовый поток, но как самая высокая кодовая точка 1114111 может вписаться в байт? Оно не может! Ладно, они также вводят DWORD, верно? Или, возможно, СЛОВО, верно? Почти верно! Они изобрели последовательности utf-8, что означает, что каждая кодовая точка выше 127 должна быть закодирована в 2-байтовую, 3-байтовую или 4-байтовую последовательность. Вот Это Да! Но как мы можем обнаружить такие последовательности? Ну, все до 127 является ASCII и является одним байтом. То, что начинается с 110, является двухбайтовой последовательностью, то, что начинается с 1110, является трехбайтовой последовательностью, а то, что начинается с 11110, является четырехбайтовой последовательностью. Остальные биты этих так называемых «стартовых байтов» принадлежат кодовой точке. Теперь в зависимости от последовательности должны следовать следующие байты. Следующий байт начинается с 10, остальные биты представляют собой 6 битов полезной нагрузки и принадлежат кодовой точке. Объедините полезные биты начального байта и следующих байтов, и вы получите кодовую точку. Вот и вся магия UTF-8.

Brighty
источник
3
Пример utf-8 знака € (евро), декодированного в 3-байтовой последовательности utf-8: E2 = 11100010 82 = 10000010 AC = 10101100 Как вы можете видеть, E2 начинается с 1110, так что это трехбайтовая последовательность. Как вы можете видеть , 82, а также AC начинается с 10, так что это следующие байты. Теперь мы объединяем «биты полезной нагрузки»: 0010 + 000010 + 101100 = 10000010101100, который является десятичным 8364, поэтому 8364 должна быть кодовой точкой для знака евро (евро).
Ярко
5

ASCII - Программное обеспечение выделяет только 8-битный байт в памяти для данного символа. Это хорошо работает для английских и принятых символов (заимствованных слов, таких как фасад), так как их соответствующие десятичные значения падают ниже 128 в десятичном значении. Пример программы C.

UTF-8 - Программное обеспечение выделяет от 1 до 4 переменных 8-битных байтов для данного символа. Что здесь подразумевается под переменной? Допустим, вы отправляете символ «A» через ваши HTML-страницы в браузере (HTML - это UTF-8), соответствующее десятичное значение A равно 65, при преобразовании его в десятичное значение становится 01000010. Для этого требуется всего 1 байт. , 1 байтовая память выделяется даже для специальных принятых английских символов, таких как «ç» в слове «фасад». Однако, если вы хотите хранить европейские символы, требуется 2 байта, поэтому вам нужен UTF-8. Однако, когда вы выбираете азиатские символы, вам требуется минимум 2 байта и максимум 4 байта. Точно так же Emoji требуют от 3 до 4 байтов. UTF-8 решит все ваши потребности.

UTF-16 выделит минимум 2 байта и максимум 4 байта на символ, он не выделит 1 или 3 байта. Каждый символ представлен 16-битным или 32-битным.

Тогда почему существует UTF-16? Первоначально Unicode был 16 бит, а не 8 бит. Ява приняла оригинальную версию UTF-16.

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

Java-программа, вызываемая веб-браузерами, использует UTF-16, но веб-браузер отправляет символы с использованием UTF-8.

Сива
источник
«Вам нигде не нужен UTF-16, если он не был принят языком или платформой»: это хороший момент, но здесь приведен неполный список: JavaScript, Java, .NET, SQL NCHAR, SQL NVARCHAR , VB4, VB5, VB6, VBA, VBScript, NTFS, Windows API….
Том Блоджет
2

UTF расшифровывается как Unicode Transformation Format. В основном в современном мире существуют сценарии, написанные на сотнях других языков, форматы которых не охватываются базовым ASCII, использованным ранее. Следовательно, UTF появился на свет.

UTF-8 имеет возможности кодирования символов, и его кодовая единица составляет 8 бит, в то время как для UTF-16 это 16 бит.

Кришна Ганеривал
источник