UTF-8 - UTF-8

UTF-8
Стандарт Стандарт Юникода
Классификация Формат преобразования Unicode , расширенный ASCII , кодирование переменной ширины
Расширяется US-ASCII
Преобразует / кодирует ISO 10646 ( Юникод )
Предшествует UTF-1

UTF-8 - это кодировка символов переменной ширины, используемая для электронного общения. Имя, определенное стандартом Unicode, является производным от формата преобразования Unicode (или универсального кодированного набора символов ) - 8-битного .

UTF-8 может кодировать все 1 112 064 действительных кодовых точки в Unicode с использованием от одного до четырех однобайтовых (8-битных) кодовых единиц. Точки кода с более низкими числовыми значениями, которые, как правило, встречаются чаще, кодируются с использованием меньшего количества байтов. Он был разработан для обратной совместимости с ASCII : первые 128 символов Unicode, которые однозначно соответствуют ASCII, кодируются с использованием одного байта с тем же двоичным значением, что и ASCII, так что действительный текст ASCII является действительным UTF-8. -кодированный Unicode. Поскольку байты ASCII не появляются при кодировании кодовых точек, отличных от ASCII, в UTF-8, UTF-8 можно безопасно использовать в большинстве языков программирования и документов, которые интерпретируют определенные символы ASCII особым образом, например /( косая черта ) в именах файлов, \( обратная косая черта ) в escape-последовательностях и %в printf .

UTF-8 был разработан как превосходная альтернатива UTF-1 , предложенной кодировке переменной ширины с частичной совместимостью с ASCII, в которой отсутствовали некоторые функции, включая самосинхронизацию и полностью совместимую с ASCII обработку символов, таких как косая черта. Кен Томпсон и Роб Пайк создали первую реализацию для операционной системы Plan 9 в сентябре 1992 года. Это привело к ее принятию X / Open в качестве спецификации для FSS-UTF , которая впервые будет официально представлена ​​на USENIX в январе 1993 года, а затем принята. по Engineering Task Force Интернет (IETF) в RFC 2277 ( BCP 18 ) для будущего интернет - стандартов работы, заменив один байт наборы символов , таких как Latin-1 в старых РЛК.

UTF-8 на сегодняшний день является наиболее распространенной кодировкой для Всемирной паутины , составляя более 97% всех веб-страниц и до 100% для некоторых языков по состоянию на 2021 год.

Именование

Официальный код Internet Assigned Numbers Authority (IANA) для кодировки - "UTF-8". Все буквы в верхнем регистре, а имя расставлено через дефис. Это написание используется во всех документах Консорциума Unicode, касающихся кодировки.

В качестве альтернативы имя « utf-8 » может использоваться всеми стандартами, соответствующими списку IANA (который включает заголовки CSS , HTML , XML и HTTP ), поскольку в объявлении регистр не учитывается.

Другие варианты, такие как те, в которых дефис опускается или заменяется пробелом, например, « utf8 » или « UTF 8 », не считаются правильными в соответствии с действующими стандартами. Несмотря на это, большинство веб-браузеров могут их понимать, и поэтому стандарты, предназначенные для описания существующей практики (например, HTML5), могут фактически требовать их признания.

Неофициально UTF-8-BOM и UTF-8-NOBOM иногда используются для текстовых файлов, которые содержат или не содержат метку порядка байтов (BOM) соответственно. Особенно в Японии кодировку UTF-8 без спецификации иногда называют « UTF-8N ».

Windows XP и более поздние версии, включая все поддерживаемые версии Windows, имеют кодовую страницу 65001 как синоним UTF-8 (поскольку Windows 7 поддерживает UTF-8 лучше), а у Microsoft есть сценарий для Windows 10 , чтобы включить его по умолчанию для его программа Microsoft Notepad .

В PCL UTF-8 называется идентификатором символа «18N» (PCL поддерживает 183 кодировки символов, называемых наборами символов, которые потенциально могут быть сокращены до единицы 18N, то есть UTF-8).

Кодирование

После ограничения кодового пространства Unicode до 21-битных значений в 2003 году, UTF-8 определен для кодирования кодовых точек от одного до четырех байтов, в зависимости от количества значащих битов в числовом значении кодовой точки. В следующей таблице показана структура кодировки. В х символы заменяются битами точки кода.

Кодовая точка <-> преобразование UTF-8
Первая кодовая точка Последняя кодовая точка Байт 1 Байт 2 Байт 3 Байт 4
U + 0000 U + 007F 0xxxxxxx
U + 0080 U + 07FF 110xxxxx 10xxxxxx
U + 0800 U + FFFF 1110xxxx 10xxxxxx 10xxxxxx
U + 10000 U + 10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

Для первых 128 символов (US-ASCII) требуется один байт. Следующие символы нужно 1920 два байта для кодирования, которая покрывает оставшуюся часть почти всех Latin-сценариев алфавитов , а также расширения ПНД , греческих , кириллических , коптской , армянской , иврит , арабский , сирийский , Тана и Письмо нко алфавитов, а также как объединение диакритических знаков . Три байта необходимы для символов в остальной части базовой многоязычной плоскости , которая содержит практически все широко используемые символы, включая большинство китайских, японских и корейских символов . Четыре байта необходимы для символов в других плоскостях Unicode , которые включают менее распространенные символы CJK , различные исторические сценарии, математические символы и эмодзи (пиктографические символы).

«Символ» на самом деле может занимать более 4 байтов, например, символ флага эмодзи занимает 8 байтов, поскольку он «построен из пары скалярных значений Unicode».

Примеры

Рассмотрим кодировку знака евро , €:

  1. Кодовая точка Unicode для «€» - U + 20AC.
  2. Поскольку эта кодовая точка находится между U + 0800 и U + FFFF, для кодирования потребуется три байта.
  3. Шестнадцатеричный 20AC является двоичным 0010 0000 10 10 1100 . Два ведущих нуля добавляются, потому что для трехбайтового кодирования требуется ровно шестнадцать битов от кодовой точки.
  4. Поскольку кодировка будет иметь длину три байта, ее ведущий байт начинается с трех единиц, затем с 0 ( 1110 ... )
  5. Четыре старших бита кодовой точки хранятся в оставшихся четырех младших битах этого байта ( 1110 0010 ), оставляя 12 битов кодовой точки, которые еще предстоит закодировать ( ... 0000 10 10 1100 ).
  6. Все байты продолжения содержат ровно шесть битов от кодовой точки. Таким образом, следующие шесть бит кодовой точки сохраняются в шести младших битах следующего байта, а 10 сохраняется в двух старших битах, чтобы пометить его как байт продолжения (так 10 000010 ).
  7. Наконец, последние шесть бит кодовой точки сохраняются в шести младших битах последнего байта, и снова 10 сохраняется в двух старших битах ( 10 10 1100 ).

Три байта 1110 0010 10 000010 10 101100 можно более кратко записать в шестнадцатеричном формате , как E2 82 AC .

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

Примеры кодировки UTF-8
Характер Двоичный код Двоичный UTF-8 Шестнадцатеричный UTF-8
$ U + 0024 010 0100 0 0100100 24
¢ U + 00A2 000 10 10 0010 110 00010 10 100010 C2 A2
U + 0939 0000 1001 00 11 1001 1110 0000 10 100100 10 111001 E0 A4 B9
U + 20AC 0010 0000 10 10 1100 1110 0010 10 000010 10 101100 E2 82 AC
U + D55C 1101 0101 01 01 1100 1110 1101 10 010101 10 011100 ED 95 9C
𐍈 U + 10348 0 00 01 0000 0011 01 00 1000 11110 000 10 010000 10 001101 10 001000 F0 90 8D 88

Восьмеричный

Использование UTF-8 шести битов на байт для представления фактических кодируемых символов означает, что восьмеричная нотация (которая использует 3-битные группы) может помочь при сравнении последовательностей UTF-8 друг с другом и при ручном преобразовании.

Восьмеричный код <-> Восьмеричное преобразование UTF-8
Первая кодовая точка Последняя кодовая точка Кодовая точка Байт 1 Байт 2 Байт 3 Байт 4
000 177 ххх ххх
0200 3777 xxyy 3xx 2гг
04000 77777 xyyzz 34x 2гг 2zz
100000 177777 1xyyzz 35x 2гг 2zz
0200000 4177777 xyyzzww 36x 2гг 2zz 2ww

В восьмеричной системе счисления произвольные восьмеричные цифры, отмеченные в таблице буквами x, y, z или w, останутся неизменными при преобразовании в UTF-8 или из него.

Пример: Á = U + 00C1 = 0301 (в восьмеричном) кодируется как 303 201 в UTF-8 (C3 81 в шестнадцатеричном).
Пример: € = U + 20AC = 20254 кодируется как 342 202 254 в UTF-8 (Е2 82 переменного тока в шестнадцатеричном).

Макет кодовой страницы

В следующей таблице обобщено использование единиц кода UTF-8 (отдельных байтов или октетов ) в формате кодовой страницы. Верхняя половина (от 0_ до 7_ ) предназначена для байтов, используемых только в однобайтовых кодах, поэтому она выглядит как обычная кодовая страница; нижняя половина предназначена для байтов продолжения (от 8_ до B_ ) и ведущих байтов (от C_ до F_ ) и объясняется далее в легенде ниже.

UTF-8
_0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _A _B _C _D _E _F
(1 байт)
0_
NUL
0000
SOH
0001
STX
0002
ETX
0003
EOT
0004
ENQ
0005
ACK
0006
BEL
0007
BS
0008
HT
0009
LF
000A
ВТ
000Б
FF
000C
CR
000D
SO
000E
SI
000F
(1)
1_
DLE
0010
DC1
0011
DC2
0012
DC3
0013
DC4
0014
NAK
0015
SYN
0016
ETB
0017
CAN
0018
EM
0019
SUB
001A
ESC
001B
FS
001C
GS
001D
RS
001E
США
001F
(1)
2_
SP
0020
!
0021
«
0022
#
0023
0024 долл. США
%
0025
&
0026
'
0027
(
0028
)
0029
*
002A
+
002B
,
002C
-
002D
.
002E
/
002F
(1)
3_
0
0030
1
0031
2
0032
3
0033
4
0034
5
0035
6
0036
7
0037
8
0038
9
0039
:
003A
;
003B
<
003C
=
003D
>
003E
?
003F
(1)
4_
@
0040
A
0041
B
0042
C
0043
D
0044
E
0045
F
0046
G
0047
H
0048
I
0049
J
004A
K
004B
L
004C
M
004D

004E
O
004F
(1)
5_
P
0050
Q
0051
R
0052
S
0053
Т
0054
U
0055
V
0056
W
0057
X
0058
Y
0059
Z
005A
[
005B
\
005C
]
005D
^
005E
_
005F
(1)
6_
`
0060

0061
b
0062
c
0063
d
0064
e
0065
f
0066
г
0067
h
0068
я
0069
j
006A
k
006B
l
006C
м
006D

006E
o
006F
(1)
7_
p
0070
q
0071
r
0072
с
0073
t
0074
u
0075
v
0076
w
0077
х
0078
y
0079
z
007A
{
007B
|
007C
}
007D
~
007E
DEL
007F

8_

+00

+01

+02

+03

+04

+05

+06

+07

+08

+09

+ 0А

+ 0B

+ 0С

+ 0D

+ 0E

+ 0F

9_

+10

+11

+12

+13

+14

+15

+16

+17

+18

+19

+ 1А

+ 1B

+ 1С

+ 1D

+ 1E

+ 1F

A_

+20

+21

+22

+23

+24

+25

+26

+27

+28

+29

+ 2А

+ 2B

+ 2С

+ 2D

+ 2E

+ 2F

B_

+30

+31

+32

+33

+34

+35

+36

+37

+38

+39

+ 3А

+ 3B

+ 3С

+ 3D

+ 3E

+ 3F
(2)
C_
2
0000
2
0040
Латинский
0080
Латинский
00C0
Латинский
0100
Латинский
0140
Латинский
0180
Латинский
01C0
Латинский
0200
IPA
0240
IPA
0280
IPA
02C0
акценты
0300
акценты
0340
Греческий
0380
Греческий
03C0
(2)
D_
Кирилл
0400
Кирилл
0440
Кирилл
0480
Кирилл
04C0
Кирилл
0500
Армени
0540
Еврейский
0580
Иврит
05C0
Арабский
0600
Арабский
0640
Арабский
0680
Арабский
06C0
Сирийский
0700
Арабский
0740
Thaana
0780
НКо
07C0
(3)
E_
Индийский
0800
Разное.
1000
Символ
2000
Кана
3000
4000 крон
5000 чешских
крон
6000 крон
7000 чешских
крон
8000 чешских
крон
9000 чешских
крон
Азиатский
A000
Хангул
B000
Хангыль
C000
Хангыль
D000
PUA
E000
PUA
F000
(4)
F_
SMP…
10000
񀀀
40000
򀀀
80000
SSP…
C0000
СПУА-Б
100000
4
140000
4
180000
4
1C0000
5
200000
5
1000000
5
2000000
5
3000000
6
4000000
6
40000000

  Синие ячейки представляют собой 7-битные (однобайтовые) последовательности. За ними не должен следовать байт продолжения.

  Оранжевые ячейки с большой точкой - это байт продолжения. Шестнадцатеричное число, показанное после символа +, представляет собой значение 6 добавляемых битов. Этот символ никогда не встречается в качестве первого байта многобайтовой последовательности.

  Белые ячейки - это ведущие байты для последовательности из нескольких байтов, длина которой указана у левого края строки. В тексте показаны блоки Unicode, закодированные последовательностями, начинающимися с этого байта, а шестнадцатеричная кодовая точка, показанная в ячейке, является наименьшим значением символа, закодированным с использованием этого ведущего байта.

  Красные клетки никогда не должны появляться в допустимой последовательности UTF-8. Первые две красные ячейки ( C0 и C1 ) могут использоваться только для 2-байтового кодирования 7-битного символа ASCII, который должен быть закодирован в 1 байт; как описано ниже, такие «слишком длинные» последовательности не допускаются. Чтобы понять, почему это так, рассмотрим символ 128, шестнадцатеричный 80 , двоичный 1000 0000 . Чтобы закодировать его как 2 символа, младшие шесть битов сохраняются во втором символе как 128, это 10 000000 , но два старших бита хранятся в первом символе как 110 00010 , что делает минимальный первый символ C2. Красные ячейки в строке F_ (от F5 до FD ) указывают ведущие байты 4-байтовых или более длинных последовательностей, которые не могут быть действительными, потому что они будут кодировать кодовые точки, превышающие предел U + 10FFFF Unicode (предел, полученный из максимальной кодовой точки кодируется в UTF-16 ). FE и FF не соответствуют ни одному разрешенному шаблону символов и поэтому не являются допустимыми стартовыми байтами.

  Розовые ячейки - это ведущие байты для последовательности из нескольких байтов, из которых допустимы некоторые, но не все возможные последовательности продолжения. E0 и F0 могут начинать чрезмерно длинное кодирование, в этом случае отображается самая низкая кодовая точка без чрезмерно длинного кодирования. F4 может запускать кодовые точки больше, чем U + 10FFFF, которые недопустимы. ED может начать кодирование кодовой точки в диапазоне U + D800 – U + DFFF; они недействительны, поскольку они зарезервированы для суррогатных половин UTF-16 .

Слишком длинные кодировки

В принципе, можно было бы увеличить количество байтов в кодировке, добавив в кодовую точку начальные нули. Чтобы закодировать знак евро € из приведенного выше примера в четырех байтах вместо трех, его можно дополнить ведущими нулями, пока он не станет длиной 21 бит - 000 000010 000010 101100 , и закодировать как 11110 000 10 000010 10 000010 10 101100 (или F0 82 82 AC в шестнадцатеричной системе счисления). Это называется слишком длинным кодированием .

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

Недействительные последовательности и обработка ошибок

Не все последовательности байтов допустимы в кодировке UTF-8. Декодер UTF-8 должен быть подготовлен для:

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

Многие из первых декодеров UTF-8 декодировали их, игнорируя неправильные биты и принимая слишком длинные результаты. Тщательно созданный недопустимый код UTF-8 может заставить их либо пропускать, либо создавать символы ASCII, такие как NUL, косую черту или кавычки. Неверный UTF-8 использовался для обхода проверок безопасности в продуктах высокого уровня, включая веб-сервер Microsoft IIS и контейнер сервлетов Apache Tomcat. RFC 3629 гласит: «Реализации алгоритма декодирования ДОЛЖНЫ защищать от декодирования недопустимых последовательностей». Стандарт Unicode требует, чтобы декодеры «... обрабатывали любую некорректно сформированную последовательность кодовых единиц как состояние ошибки. Это гарантирует, что они не будут интерпретировать и генерировать некорректно сформированную последовательность кодовых единиц».

Начиная с RFC 3629 (ноябрь 2003 г.), верхняя и нижняя суррогатные половины, используемые UTF-16 (от U + D800 до U + DFFF), и кодовые точки, не кодируемые UTF-16 (те, которые находятся после U + 10FFFF), не являются допустимыми значениями Unicode, и их кодировка UTF-8 должна рассматриваться как недопустимая последовательность байтов. Отсутствие декодирования непарных суррогатных половин делает невозможным сохранение недопустимого UTF-16 (например, имен файлов Windows или UTF-16, который был разделен между суррогатами) как UTF-8, в то время как это возможно с WTF-8 .

Некоторые реализации декодеров выдают исключения при ошибках. У этого есть недостаток, заключающийся в том, что он может превратить то, что в противном случае было бы безобидными ошибками (такими как ошибка «нет такого файла»), в отказ в обслуживании . Например, ранние версии Python 3.0 будут немедленно завершаться, если переменные командной строки или среды содержат недопустимый UTF-8. Альтернативный способ - заменить ошибки символом замены. Начиная с Unicode 6 (октябрь 2010 г.), стандарт (глава 3) рекомендовал «наилучшую практику», при которой ошибка заканчивается, как только встречается запрещенный байт. В этих декодерах E1, A0, C0 есть две ошибки (2 байта в первом). Это означает, что длина ошибки не превышает трех байтов, и она никогда не содержит начало действительного символа, и существует 21 952 различных возможных ошибки. Стандарт также рекомендует заменять каждую ошибку символом замены " " (U + FFFD).

Отметка порядка байтов

Если знак порядка байтов Unicode UTF-16 (BOM, U + FEFF) находится в начале файла UTF-8, первые три байта будут 0xEF , 0xBB , 0xBF .

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

Некоторые языки программирования и форматы файлов имеют собственный способ маркировки использования кодировок, таких как UTF-8, в исходном коде. Примеры включают HTML <meta charset="UTF-8"/> и Python 2.7. # coding: utf-8

Принятие

Использование основных кодировок в Интернете с 2001 по 2012 год, как было зарегистрировано Google, при этом UTF-8 обогнал все остальные в 2008 году и более 60% веб-кодировок в 2012 году (с тех пор приближается к 100%). ASCII -только цифра включает в себя все веб - страницы , которые содержат только ASCII - символы, независимо от заявленного заголовка.

UTF-8 - это рекомендация WHATWG для спецификаций HTML и DOM , а Internet Mail Consortium рекомендует, чтобы все программы электронной почты могли отображать и создавать почту с использованием UTF-8. World Wide Web Consortium рекомендует UTF-8 в качестве кодировки по умолчанию в XML и HTML (а не только с использованием UTF-8, а также с указанием его в метаданных), «даже тогда , когда все символы в ASCII диапазоне .. Использование не-UTF- 8 кодировок могут привести к неожиданным результатам ». Многие другие стандарты поддерживают только UTF-8, например, этого требует открытый обмен JSON .

UTF-8 является наиболее распространенной кодировкой для Всемирной паутины с 2008 года. По состоянию на октябрь 2021 года на UTF-8 приходится в среднем 97,3% всех веб-страниц; и 988 из 1000 самых популярных веб-страниц. UTF-8 включает ASCII как подмножество; почти ни один веб-сайт не объявляет об использовании только ASCII. В нескольких языках 100,0% используется UTF-8.

Для локальных текстовых файлов Использование UTF-8 меньше, и многие из устаревших однобайтные (и КИХ многобайтовые) кодировок остаются в использовании. Основная причина - редакторы, которые не отображают и не записывают UTF-8, если первый символ в файле не является меткой порядка байтов (BOM), что делает невозможным использование UTF-8 другим программным обеспечением без перезаписи, чтобы игнорировать метку порядка байтов. на входе и добавить на выходе. Недавно произошли некоторые улучшения: Блокнот в Windows 10 по умолчанию записывает UTF-8 без спецификации, а для некоторых системных файлов в Windows 11 требуется UTF-8, а почти все файлы в macOS и Linux должны иметь кодировку UTF-8 (без спецификация). Java со своим NIO API по умолчанию читает и записывает файлы UTF-8 и переходит к такому же принципу для всех других файловых API. Он уже работает для всех API на большинстве платформ, кроме Windows . «Выбор UTF-8 применяется только к стандартным API Java, а не к языку Java, который будет продолжать использовать UTF-16». Многие другие языки программирования по умолчанию используют UTF-8 для ввода-вывода; или планируете перейти на UTF-8, например Python, который готовится «изменить кодировку по умолчанию на UTF-8 [поскольку она] стала фактически стандартной кодировкой текста». Большинство баз данных поддерживают UTF-8 (иногда единственный вариант, как для некоторых форматов файлов), в том числе Microsoft, начиная с SQL Server 2019, что приводит к увеличению скорости на 35% и «почти 50% снижению требований к хранилищу».

Внутреннее использование программного обеспечения ниже, с использованием UTF-16 или UCS-2 , особенно в Windows, но также с помощью JavaScript , Python , Qt и многих других межплатформенных программных библиотек. Совместимость с Windows API является основной причиной этого, хотя вера в то, что прямая индексация BMP улучшает скорость, также была важным фактором. Более новое программное обеспечение начало использовать UTF-8: строковый примитив по умолчанию, используемый в Go , Julia , Rust , Swift 5 и PyPy, - это UTF-8, будущая версия Python намеревается хранить строки как UTF-8 и современные версии из Microsoft Visual Studio использование UTF-8 внутренне (однако все еще требует ключ командной строки для чтения или записи UTF-8). UTF-8 - это «единственная кодировка текста, которая должна поддерживаться стандартом C ++», начиная с C ++ 20 . По состоянию на май 2019 года Microsoft изменила свой курс, поддерживая только UTF-16 для Windows API, предоставив возможность установить UTF-8 в качестве «кодовой страницы» для многобайтового API (ранее это было невозможно), а теперь Microsoft рекомендует (программистам) использовать UTF-8 для приложений универсальной платформы Windows (UWP), продолжая поддерживать устаревший интерфейс «Unicode» (то есть UTF-16).

История

Международная организация по стандартизации (ИСО) устанавливают , чтобы составить универсальный многобайтную набор символов в 1989 проект ИСО 10646 стандарт содержал не-требуемое приложение под названием UTF-1 , который обеспечил байтовый поток кодирование его 32-битных кодовых точек . Эта кодировка была неудовлетворительной с точки зрения производительности, среди других проблем, и самая большая проблема, вероятно, заключалась в том, что в ней не было четкого разделения между ASCII и не-ASCII: новые инструменты UTF-1 будут обратно совместимы с текстом в кодировке ASCII, но Текст в кодировке UTF-1 может сбить с толку существующий код, ожидающий ASCII (или расширенный ASCII ), потому что он может содержать байты продолжения в диапазоне 0x21–0x7E, что означает что-то еще в ASCII, например, 0x2F для '/', разделителя путей в Unix. , и этот пример отражен в названии и вводном тексте его замены. Приведенная ниже таблица была составлена ​​на основе текстового описания в приложении.

UTF-1
Количество
байтов
Первая
кодовая точка
Последняя
кодовая точка
Байт 1 Байт 2 Байт 3 Байт 4 Байт 5
1 U + 0000 U + 009F 00–9F
2 U + 00A0 U + 00FF A0 A0 – FF
2 U + 0100 U + 4015 A1 – F5 21–7E, A0 – FF
3 U + 4016 U + 38E2D F6 – FB 21–7E, A0 – FF 21–7E, A0 – FF
5 U + 38E2E U + 7FFFFFFF FC – FF 21–7E, A0 – FF 21–7E, A0 – FF 21–7E, A0 – FF 21–7E, A0 – FF

В июле 1992 года комитет X / Open XoJIG искал лучшую кодировку. Дэйв Проссер из Unix System Laboratories представил предложение о более быстрой реализации и внесло улучшение, заключающееся в том, что 7-битные символы ASCII будут представлять только себя; все многобайтовые последовательности будут включать только байты, в которых установлен старший бит. Название File System Safe UCS Transformation Format (FSS-UTF) и большая часть текста этого предложения были позже сохранены в окончательной спецификации.

FSS-UTF

Предложение FSS-UTF (1992)
Количество
байтов
Первая
кодовая точка
Последняя
кодовая точка
Байт 1 Байт 2 Байт 3 Байт 4 Байт 5
1 U + 0000 U + 007F 0xxxxxxx
2 U + 0080 U + 207F 10xxxxxx 1xxxxxxx
3 U + 2080 U + 8207F 110xxxxx 1xxxxxxx 1xxxxxxx
4 U + 82080 U + 208207F 1110xxxx 1xxxxxxx 1xxxxxxx 1xxxxxxx
5 U + 2082080 U + 7FFFFFFF 11110xxx 1xxxxxxx 1xxxxxxx 1xxxxxxx 1xxxxxxx

В августе 1992 года это предложение было разослано заинтересованным сторонам представителем IBM X / Open. Модификация, внесенная Кеном Томпсоном из группы операционной системы Plan 9 в Bell Labs, сделала ее несколько менее эффективной по сравнению с предыдущим предложением, но, что очень важно, позволила ей быть самосинхронизирующейся , позволяя читателю начать с любого места и немедленно обнаруживать границы последовательности байтов. Он также отказался от использования предубеждений и вместо этого добавил правило, согласно которому допускается только кратчайшее кодирование; дополнительная потеря компактности относительно невелика, но теперь читатели должны искать недопустимые кодировки, чтобы избежать проблем с надежностью и особенно безопасностью. Дизайн Томпсона был обрисован 2 сентября 1992 года на салфетке в закусочной в Нью-Джерси вместе с Робом Пайком . В последующие дни Пайк и Томпсон внедрили его и обновили Plan 9, чтобы использовать его повсюду, а затем сообщили о своем успехе X / Open, который принял его в качестве спецификации для FSS-UTF.

FSS-UTF (1992) / UTF-8 (1993)
Количество
байтов
Первая
кодовая точка
Последняя
кодовая точка
Байт 1 Байт 2 Байт 3 Байт 4 Байт 5 Байт 6
1 U + 0000 U + 007F 0xxxxxxx
2 U + 0080 U + 07FF 110xxxxx 10xxxxxx
3 U + 0800 U + FFFF 1110xxxx 10xxxxxx 10xxxxxx
4 U + 10000 U + 1FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5 U + 200000 U + 3FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6 U + 4000000 U + 7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

UTF-8 был впервые официально представлен на конференции USENIX в Сан-Диего с 25 по 29 января 1993 года. Инженерная группа Интернета приняла UTF-8 в своей Политике в отношении наборов символов и языков в RFC 2277 ( BCP 18) для будущего Интернета. стандарты работают, заменяя однобайтовые наборы символов, такие как Latin-1, в старых RFC.

В ноябре 2003 года UTF-8 был ограничен RFC  3629, чтобы соответствовать ограничениям кодировки символов UTF-16 : явный запрет кодовых точек, соответствующих старшим и младшим суррогатным символам, удалил более 3% трехбайтовых последовательностей и завершил при U + 10FFFF удаляется более 48% четырехбайтовых последовательностей и всех пяти- и шестибайтовых последовательностей.

Стандарты

В различных стандартах есть несколько текущих определений UTF-8:

  • RFC  3629 / STD 63 (2003), который устанавливает UTF-8 в качестве стандартного элемента Интернет-протокола.
  • RFC  5198 определяет UTF-8 NFC для сетевого обмена (2008 г.)
  • ИСО / МЭК 10646: 2014 §9.1 (2014)
  • Стандарт Unicode, версия 11.0 (2018)

Они заменяют определения, данные в следующих устаревших работах:

  • Стандарт Unicode, версия 2.0 , приложение A (1996)
  • ИСО / МЭК 10646-1: 1993 Поправка 2 / Приложение R (1996)
  • RFC  2044 (1996)
  • RFC  2279 (1998)
  • Стандарт Unicode, версия 3.0 , §2.3 (2000) плюс исправление № 1: кратчайшая форма UTF-8 (2000)
  • Стандартное приложение Unicode # 27: Unicode 3.1 (2001)
  • Стандарт Unicode, версия 5.0 (2006 г.)
  • Стандарт Unicode, версия 6.0 (2010 г.)

Все они одинаковы по своей общей механике, с основными различиями в таких вопросах, как допустимый диапазон значений кодовой точки и безопасная обработка недопустимого ввода.

Сравнение с другими кодировками

Вот некоторые из важных особенностей этой кодировки:

  • Обратная совместимость: обратная совместимость с ASCII и огромное количество программного обеспечения, предназначенного для обработки текста в кодировке ASCII, были основной движущей силой дизайна UTF-8. В UTF-8 отдельные байты со значениями в диапазоне от 0 до 127 сопоставляются непосредственно с кодовыми точками Unicode в диапазоне ASCII. Отдельные байты в этом диапазоне представляют символы, как и в ASCII. Более того, 7-битные байты (байты, где самый старший бит равен 0) никогда не появляются в многобайтовой последовательности, и никакая допустимая многобайтовая последовательность не декодируется в кодовую точку ASCII. Последовательность 7-битных байтов является допустимой как ASCII, так и допустимой UTF-8, и при любой интерпретации представляет одну и ту же последовательность символов. Следовательно, 7-битные байты в потоке UTF-8 представляют все и только символы ASCII в потоке. Таким образом, многие текстовые процессоры, синтаксические анализаторы, протоколы, форматы файлов, программы отображения текста и т. Д., Которые используют символы ASCII для форматирования и управления, будут продолжать работать так, как задумано, обрабатывая поток байтов UTF-8 как последовательность одиночных символов. байтовые символы, без декодирования многобайтовых последовательностей. Символы ASCII, на которых выполняется обработка, такие как знаки препинания, пробелы и управляющие символы, никогда не будут кодироваться как многобайтовые последовательности. Поэтому такие процессоры могут просто игнорировать или передавать многобайтовые последовательности без их декодирования. Например, пробелы ASCII могут использоваться для токенизации потока UTF-8 в слова; Перевод строки ASCII может использоваться для разделения потока UTF-8 на строки; и символы ASCII NUL могут использоваться для разделения данных в кодировке UTF-8 на строки с завершающим нулем. Точно так же многие строки формата, используемые библиотечными функциями, такими как printf, будут правильно обрабатывать входные аргументы в кодировке UTF-8.
  • Откат и автоматическое обнаружение: только небольшое подмножество возможных байтовых строк является допустимой строкой UTF-8: байты от C0, C1 и F5 до FF не могут отображаться, а байты с установленным старшим битом должны быть парами, и другие требования . Крайне маловероятно, что читаемый текст в любом расширенном ASCII является допустимым UTF-8. Частично популярность UTF-8 связана с тем, что он также обеспечивает обратную совместимость для них. Процессор UTF-8, который ошибочно принимает расширенный ASCII в качестве входных данных, может, таким образом, "автоматически определять" это с очень высокой надежностью. Откатные ошибки будут ложноотрицательными, и они будут редкими. Более того, во многих приложениях, таких как отображение текста, последствия неправильного отката обычно незначительны. Поток UTF-8 может просто содержать ошибки, в результате чего схема автоматического обнаружения дает ложные срабатывания; но автоматическое определение в большинстве случаев оказывается успешным, особенно с более длинными текстами, и широко используется. Он также работает для «отката» или замены 8-битных байтов с использованием соответствующей кодовой точки для устаревшей кодировки только при обнаружении ошибок в UTF-8, что позволяет восстановление, даже если UTF-8 и устаревшая кодировка объединены в одном и том же файл.
  • Код префикса : первый байт указывает количество байтов в последовательности. Чтение из потока может мгновенно декодировать каждую отдельную полностью принятую последовательность без предварительного ожидания первого байта следующей последовательности или индикации конца потока. Длину многобайтовых последовательностей люди легко определяют, поскольку это просто количество старших единиц в ведущем байте. Некорректный символ не будет декодирован, если поток заканчивается на середине последовательности.
  • Самосинхронизация : ведущие байты и байты продолжения не имеют общих значений (байты продолжения начинаются с битов 10 , отдельные байты начинаются с 0, а более длинные ведущие байты начинаются с 11 ). Это означает, что поиск случайно не найдет последовательность для одного символа, начинающегося в середине другого символа. Это также означает, что начало символа может быть найдено из случайной позиции путем резервного копирования не более 3 байтов, чтобы найти ведущий байт. Некорректный символ не будет декодирован, если поток начинается с середины последовательности, а более короткая последовательность никогда не появится внутри более длинной.
  • Порядок сортировки: выбранные значения ведущих байтов означают, что список строк UTF-8 может быть отсортирован в порядке кодовых точек путем сортировки соответствующих последовательностей байтов.

Однобайтовый

  • UTF-8 может кодировать любой символ Unicode , избегая необходимости вычислять и устанавливать « кодовую страницу » или иным образом указывать, какой набор символов используется, и позволяя выводить данные в нескольких сценариях одновременно. Для многих сценариев использовалось более одной однобайтовой кодировки, поэтому даже знание сценария было недостаточной информацией для его правильного отображения.
  • Байты 0xFE и 0xFF не отображаются, поэтому допустимый поток UTF-8 никогда не соответствует метке порядка байтов UTF-16 и, следовательно, не может быть перепутан с ним. Отсутствие 0xFF (0377) также устраняет необходимость экранирования этого байта в Telnet (и управляющем соединении FTP).
  • Текст в кодировке UTF-8 больше специализированных однобайтовых кодировок, за исключением простых символов ASCII. В случае скриптов, которые использовали 8-битные наборы символов с нелатинскими символами, закодированными в верхней половине (например, большинство кодовых страниц кириллицы и греческого алфавита ), символы в UTF-8 будут вдвое больше. Для некоторых шрифтов, таких как тайский и деванагари (который используется в различных языках Южной Азии), символы будут утроены. Есть даже примеры, когда один байт превращается в составной символ в Unicode и, таким образом, в шесть раз больше в UTF-8. Это вызвало возражения в Индии и других странах.
  • В UTF-8 (или в любой другой кодировке переменной длины) можно разделить или обрезать строку в середине символа. Если эти две части не будут повторно добавлены позже перед интерпретацией как символы, это может привести к недопустимой последовательности как в конце предыдущего раздела, так и в начале следующего, а некоторые декодеры не сохранят эти байты и приведут к потере данных. Поскольку UTF-8 самосинхронизируется, он никогда не будет вводить другой допустимый символ, а также довольно легко переместить точку усечения назад к началу символа.
  • Если все кодовые точки имеют одинаковый размер, легко измерить их фиксированное количество. Из-за документации эпохи ASCII, где «символ» используется как синоним «байта», это часто считается важным. Однако, измеряя позиции строк с использованием байтов вместо «символов», большинство алгоритмов можно легко и эффективно адаптировать для UTF-8. Например, поиск строки в длинной строке может выполняться побайтово; свойство самосинхронизации предотвращает ложные срабатывания.

Другой многобайтовый

  • UTF-8 может кодировать любой символ Юникода . Файлы в разных сценариях могут отображаться правильно без необходимости выбора правильной кодовой страницы или шрифта. Например, китайский и арабский языки могут быть записаны в одном файле без специальной разметки или ручных настроек, указывающих кодировку.
  • UTF-8 является самосинхронизирующимся : границы символов легко идентифицируются путем сканирования четко определенных битовых шаблонов в любом направлении. Если байты потеряны из-за ошибки или повреждения , всегда можно найти следующий допустимый символ и возобновить обработку. Если необходимо сократить строку, чтобы она соответствовала указанному полю, можно легко найти предыдущий допустимый символ. Многие многобайтовые кодировки, такие как Shift JIS , гораздо сложнее повторно синхронизировать. Это также означает, что байтовые алгоритмы поиска строк могут использоваться с UTF-8 (поскольку символ - это то же самое, что и «слово», состоящее из такого количества байтов), оптимизированные версии поиска байтов могут быть намного быстрее благодаря аппаратному обеспечению. таблицы поддержки и поиска, содержащие всего 256 записей. Однако самосинхронизация требует, чтобы биты были зарезервированы для этих маркеров в каждом байте, увеличивая размер.
  • Эффективно кодировать с помощью простых побитовых операций . UTF-8 не требует более медленных математических операций, таких как умножение или деление (в отличие от Shift JIS , GB 2312 и других кодировок).
  • UTF-8 займет больше места, чем многобайтовая кодировка, разработанная для конкретного скрипта. Унаследованные восточноазиатские кодировки обычно использовали два байта на символ, но в UTF-8 занимали три байта на символ.

UTF-16

  • Байтовые кодировки и UTF-8 представлены в программах байтовыми массивами, и часто ничего не нужно делать с функцией при преобразовании исходного кода из байтовой кодировки в UTF-8. UTF-16 представлен массивами 16-битных слов, и преобразование в UTF-16 при сохранении совместимости с существующими программами на основе ASCII (например, как это было сделано с Windows) требует, чтобы каждый API и структура данных, которая принимает строку для дублирования, одна версия принимает байтовые строки, а другая версия принимает UTF-16. Если обратная совместимость не требуется, необходимо изменить всю обработку строк.
  • Текст, закодированный в UTF-8, будет меньше, чем тот же текст, закодированный в UTF-16, если кодовых точек ниже U + 0080 больше, чем в диапазоне U + 0800..U + FFFF. Это верно для всех современных европейских языков. Это часто верно даже для таких языков, как китайский, из-за большого количества пробелов, новых строк, цифр и разметки HTML в типичных файлах.
  • Большая часть коммуникаций (например, HTML и IP) и хранилища (например, для Unix) была разработана для потока байтов . Строка UTF-16 должна использовать пару байтов для каждой единицы кода:
    • Порядок этих двух байтов становится проблемой и должен быть указан в протоколе UTF-16, например, с пометкой порядка байтов .
    • Если нечетное количество байтов отсутствует в UTF-16, вся остальная часть строки будет бессмысленным текстом. Любые байты, отсутствующие в UTF-8, по-прежнему позволяют точно восстановить текст, начиная со следующего символа после отсутствующих байтов.

Производные

Следующие реализации показывают небольшие отличия от спецификации UTF-8. Они несовместимы со спецификацией UTF-8 и могут быть отклонены соответствующими приложениями UTF-8.

ЦЭСУ-8

В техническом отчете № 26 Unicode имя CESU-8 присваивается нестандартному варианту UTF-8, в котором символы Unicode в дополнительных плоскостях кодируются с использованием шести байтов, а не четырех байтов, требуемых UTF-8. Кодировка CESU-8 обрабатывает каждую половину четырехбайтовой суррогатной пары UTF-16 как двухбайтовый символ UCS-2, в результате чего получается два трехбайтовых символа UTF-8, которые вместе представляют исходный дополнительный символ. Символы Unicode в базовой многоязычной плоскости отображаются так же, как обычно в UTF-8. Отчет был написан для подтверждения и формализации существования данных, закодированных как CESU-8, несмотря на то, что Консорциум Unicode не одобряет его использование, и отмечает, что возможной преднамеренной причиной кодирования CESU-8 является сохранение двоичного сопоставления UTF-16.

Кодирование CESU-8 может быть результатом преобразования данных UTF-16 с дополнительными символами в UTF-8 с использованием методов преобразования, которые принимают данные UCS-2, что означает, что они не знают о четырехбайтовых дополнительных символах UTF-16. Это в первую очередь проблема операционных систем, которые широко используют UTF-16 для внутренних целей, таких как Microsoft Windows .

В Oracle Database для UTF8набора символов используется кодировка CESU-8, и эта кодировка считается устаревшей. Набор AL32UTF8символов использует совместимую со стандартами кодировку UTF-8 и является предпочтительной.

CESU-8 запрещено использовать в документах HTML5 .

MySQL utf8mb3

В MySQL , то utf8mb3набор символов определяется как UTF-8 закодированные данные с максимум три байта на символ, а это означает только Unicode символы в Basic Multilingual Plane (т.е. от UCS-2 ) поддерживаются. Символы Unicode в дополнительных плоскостях явно не поддерживаются. utf8mb3устарел в пользу utf8mb4набора символов, который использует совместимую со стандартами кодировку UTF-8. utf8является псевдонимом для utf8mb3, но предполагается, что он станет псевдонимом utf8mb4в будущей версии MySQL. Можно, хотя и не поддерживается, хранить данные в utf8mb3кодировке CESU-8 , обрабатывая данные UTF-16 с дополнительными символами, как если бы они были UCS-2.

Модифицированный UTF-8

Модифицированный UTF-8 (MUTF-8) возник на языке программирования Java . В модифицированном UTF-8 нулевой символ (U + 0000) использует двухбайтовую сверхдлинную кодировку 110 00000 10 000000 (шестнадцатеричное C0 80 ) вместо 00000000 (шестнадцатеричное 00 ). Модифицированные строки UTF-8 никогда не содержат никаких фактических нулевых байтов, но могут содержать все кодовые точки Unicode, включая U + 0000, что позволяет обрабатывать такие строки (с добавленным нулевым байтом) традиционными строковыми функциями с нулевым символом в конце . Все известные реализации модифицированного UTF-8 также обрабатывают суррогатные пары, как в CESU-8 .

При обычном использовании язык поддерживает стандартный UTF-8 при чтении и записи строк через InputStreamReaderи OutputStreamWriter(если это набор символов платформы по умолчанию или по запросу программы). Однако он использует модифицированный UTF-8 для сериализации объектов среди других приложений DataInputи DataOutputдля собственного интерфейса Java , а также для встраивания константных строк в файлы классов .

Формат dex, определенный Dalvik, также использует тот же модифицированный UTF-8 для представления строковых значений. Tcl также использует тот же модифицированный UTF-8, что и Java, для внутреннего представления данных Unicode, но использует строгий CESU-8 для внешних данных.

WTF-8

В WTF-8 (формат шаткого преобразования, 8 бит) разрешены непарные суррогатные половинки (от U + D800 до U + DFFF). Это необходимо для хранения возможно недопустимого UTF-16, например, имен файлов Windows. Многие системы, работающие с UTF-8, работают таким образом, не считая его другой кодировкой, поскольку это проще.

(Термин «WTF-8» также юмористически используется для обозначения ошибочно дважды закодированного UTF-8, иногда подразумевая, что кодируются только байты CP1252 .)

PEP 383

Версия 3 языка программирования Python обрабатывает каждый байт недопустимого байтового потока UTF-8 как ошибку (см. Также изменения с новым режимом UTF-8 в Python 3.7); это дает 128 различных возможных ошибок. Были созданы расширения, позволяющие преобразовывать без потерь любую последовательность байтов, которая, как предполагается, является UTF-8, в UTF-16 или UTF-32, переводя 128 байтов возможных ошибок в зарезервированные кодовые точки и преобразовывая эти кодовые точки обратно в ошибки. байтов для вывода UTF-8. Наиболее распространенный подход - преобразовать коды в U + DC80 ... U + DCFF, которые являются низкими (замыкающими) суррогатными значениями и, следовательно, «недействительными» UTF-16, как используется Python PEP 383 (или «surrogateescape»). подход. Другая кодировка под названием MirBSD OPTU-8/16 преобразует их в U + EF80 ... U + EFFF в области частного использования . В любом подходе значение байта кодируется в младших восьми битах выходной кодовой точки.

Эти кодировки очень полезны, потому что они позволяют избежать необходимости иметь дело с «недопустимыми» байтовыми строками намного позже, если вообще позволяют, и позволяют байтовым массивам «текст» и «данные» быть одним и тем же объектом. Если программа хочет использовать UTF-16 внутри, они должны сохранять и использовать имена файлов, которые могут использовать недопустимый UTF-8; поскольку API файловой системы Windows использует UTF-16, необходимость в поддержке недопустимого UTF-8 меньше.

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

Смотрите также

Примечания

использованная литература

внешние ссылки