Разное

Utf8 encode: PHP: utf8_encode — Manual

Содержание

encodeURI() — JavaScript | MDN

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

Предполагается, что URI является полным URI, поэтому метод не кодирует зарезервированные символы, имеющие особое значение в URI.

encodeURI заменяет все символы, кроме следующих с соответствующими UTF-8 управляющими последовательностями:

Зарезервированные символы; , / ? : @ & = + $
Неэкранируемые символылатинские буквы, десятичные цифры, - _ . ! ~ * ' ( )
Score#

Заметим, что encodeURI сам по себе не может сформировать правильные HTTP GET и POST запросы, такие как XMLHTTPRequests, потому, что «&», «+», и «=» не закодированы, которые воспринимаются как специальные символы в GET и POST запросах. encodeURIComponent, однако, кодирует эти символы

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


console.log(encodeURIComponent('\uD800\uDFFF'));


console.log(encodeURIComponent('\uD800'));


console.log(encodeURIComponent('\uDFFF'));

Также заметим, что следуя наиболее свежей RFC3986 для URL, которая делает квадратные скобки защищёнными (для IPv6) и таким образом не кодирует, когда формирование чего-либо, не являющегося частью URL (такое как домен), следующий сниппет поможет:

function fixedEncodeURI (str) {
    return encodeURI(str). replace(/%5B/g, '[').replace(/%5D/g, ']');
}

Юникод в Python — Введение в Python

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

Unicode in Python

Before the Unicode

  • Memory consists of bytes
  • A string is a chain of bytes
  • One byte can have up to 256 values
  • One byte can mark one of 256 symbols
  • To print a byte, you should find a symbol that it marks…
  • … with a special table, named Code page

ASCII Code page

  • a special table that compares bytes with symbols
  • ASCII table as a standard
  • 0..127 for latin and system symbols
  • 128..255 for extended symbols

How about foreign languages?

  • 0..127 for latin and system symbols anyway
  • 128..255 for realm-specific symbols
  • One realm — one code page
  • cp866 DOS-Cyrillic
  • cp1251 Windows-Cyrillic
  • cp1253 Windows-Creek
  • etc

Encoding hell

  • Lots of code pages
  • Every message should declare the code page
  • Encode/decode errors, strange symbols instead of text
  • Remember your inbox 10 years ago

How does it fail

  • User A types "Привет" on Linux (utf-8)
  • The bytes are \xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82
  • The program should send a header with encoding, but it doesn’t
  • User B receives the message without header on Windows (cp1251)
  • So default code page becomes cp1251
  • Decoded message is Привет
  • :—(

The solution is Unicode

  • It’s a common unlimited alphabet
  • Every symbol has its own number
  • Unicode is growing
  • U+XXXX to refer a specific code
U+0031      1
U+00A9      ©
U+20AC      €
U+266B      ♫
U+4E64      乤
U+45B4      䖴

What is UTF?

  • An algorithm how turn Unicode into bytes and read it back
  • There are UTF-8, -16 and -32 encodings
  • UTF-8 uses 1 byte for latin and 2 bytes for non-latin
  • UTF-8 is compatible with english text
  • Can encode large subset of Unicode

Still have problems with Unicode?

  • Try to use UTF-8 encoding everywhere
  • Read Joel Spolsky «About Unicode and Character Sets»

Unicode in Python 2. x

  • Unicode strings are declared with u'...' prefix
  • The should be coding directive in your file
  • Use \uXXXX to refer unicode symbols 0..FFFF
  • \UXXXXXXXX to refer 0..FFFFFFFF symbols (rare)
# coding=utf-8           # -*- coding: utf-8 -*-
name = u'Иван'
name = u'Ιαννης'
name = u'João'
greet = u'\u041f\u0440\u0438\u0432\u0435\u0442'
print greet
>>> Привет
print u'\U0000041f\U00000440\U00000438\U00000432\U00000435\U00000442'
>>> Привет

data = u"""
Any string in english
Любая строка на русском
任何字符串在中國"""

print data
Any string in english
Любая строка на русском
任何字符串在中國

repr(data)
u'\nAny string in english\n\u041b\u044e\u0431\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c\n\u4efb\u4f55\u5b57\u7b26\u4e32\u5728\u4e2d\u570b\n'

How to turn an object into Unicode

unicode([1, 2, True, {"test": 42}])
>>> u"[1, 2, True, {'test': 42}]"

unicode(obj) == obj. __unicode__()

class User(object):
    def __unicode__(self):
        return u'%s %s' % (self.name, self.surname)

user = User(...)
unicode(user)  # u'Михаил Паниковский'

How to turn a 8-bit string into Unicode

message = '\xcf\xf0\xe8\xe2\xe5\xf2'
decoded = message.decode('cp1251')
repr(decoded)
>>> u'\u041f\u0440\u0438\u0432\u0435\u0442'
print decoded
Привет

message = '\x8f\xe0\xa8\xa2\xa5\xe2'
decoded = unicode(message, 'cp866')
>>> Привет

How to turn a Unicode into 8-bit string

udata = u'Сообщение'
udata.encode('cp1251')
>>> '\xd1\xee\xee\xe1\xf9\xe5\xed\xe8\xe5'
udata.encode('utf-8')
>>> '\xd0\xa1\xd0\xbe\xd0\xbe\xd0\xb1\xd1\x89\xd0\xb5\xd0\xbd\xd0\xb8'

Encode/decode chaining

u'Иван'.encode('cp866').decode('cp866')
>>> u'\u0418\u0432\u0430\u043d'

'\x88\xa2\xa0\xad'.decode('cp866').encode('utf-8')
>>> '\xd0\x98\xd0\xb2\xd0\xb0\xd0\xbd'

Encode/Decode errors

>>> u'Ivan'. encode('cp1251')
'Ivan'

>>> u'Иван'.encode('cp1251')
'\xc8\xe2\xe0\xed'

>>> u'任何字符串在中國'.decode('cp1251')
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-7: ordinal not in range(128)

The meaning of strings

  • Unicode is a human string
  • 8-bit string is just bytes
  • Avoid printing bytes
  • The result depends on locale, code page, etc

Don’t mix unicode and 8-bit strings!

u'Привет, ' + 'Ivan'
Привет, Ivan

u'Привет, ' + 'Иван'
>>> UnicodeDecodeError: 'ascii' codec can't decode byte 0xd0 in position 0: ordinal not in range(128)

name = '\xd0\x98\xd0\xb2\xd0\xb0\xd0\xbd'
u'Привет, ' + name.decode('utf-8')
>>> Привет, Иван

Methods are same

data = u'Юникод и Ко'
data.upper()                # ЮНИКОД И КО
data.lower()                # юникод и ко
data.split(u' ')
>>> [u'\u042e\u043d\u0438\u043a\u043e\u0434', u'\u0438', u'\u041a\u043e']
data. replace(u'Ко', u'Компания')       # Юникод и Компания

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >

Нашли опечатку или неточность?

Выделите текст, нажмите
ctrl + enter
и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Исчерпывающее руководство по Юникоду и кодировке символов в Python

Работа с кодировкой символов на Python, да и на любом другом языке, временами выглядит довольно сложной. На Stack Overflow можно найти тысячи вопросов, посвящённых таким исключениям, как UnicodeDecodeError и UnicodeEncodeError. Данное руководство призвано прояснить сложные аспекты работы с этими исключениями и продемонстрировать, что работа с текстовыми и двоичными данными на Python 3 может быть приятной. В Python хорошо реализована поддержка Юникода, однако для работы с кодировкой всё же потребуется приложить усилия.

Вводная часть статьи даст общее понимание работы с Юникодом, не привязанное к какому-то определённому языку, однако практические примеры будут приведены именно на Python, а их описание будет довольно лаконичным.

Изучив эту статью, вы:
  • Освоите концепции кодировки символов и системы нумерации;
  • Поймёте, как кодировка работает с объектами str и bytes;
  • Узнаете, как в Python поддерживается система нумерации посредством различных форм литералов int;
  • Познакомитесь со встроенными функциями языка, относящимися к кодировке и системе нумерации.

Система нумерации и кодировка символов настолько тесно связаны, что их придётся раскрыть в одном руководстве, в противном случае материал будет неполным.

Прим. Статья ориентирована на Python 3, а все примеры кода созданы с помощью оболочки CPython 3.7.2. Большая часть более ранних версий Python 3 также будут корректно обрабатывать код. Если вы всё ещё используете Python 2 и различия в обработке текста и бинарных данных между 2 и 3 версиями языка вас отпугивают, это руководство может помочь вам преодолеть барьер.

Что такое кодировка символов?

Существуют десятки, если не сотни, кодировок символов. Понять эту концепцию легче всего, разобрав одну из самых простых, ASCII.

Независимо от того, занимаетесь вы самообразованием или получили более формальное образование в сфере IT , наверняка пару раз вы уже видели таблицу ASCII. Эта таблица — хорошее начало для изучения принципов кодировки, так как она простая и маленькая (как вы увидите дальше, даже слишком маленькая).

Она охватывает следующее:

  • Символы английского алфавита в нижнем регистре: от a до z;
  • Символы английского алфавита в верхнем регистре: от A до Z;
  • Некоторые знаки препинания и символы: например «$» или «!»;
  • Символы, отображаемые как пустое место: пробел (« »), символ новой строки, возврата каретки, горизонтальной и вертикальной табуляции и несколько других;
  • Некоторые непечатаемые символы: такие как бекспейс, «\b», которые просто невозможно отобразить, так, как к примеру, букву А.

Приведём формальное определение кодировки символов.

На самом высоком уровне — это способ перевода символов (таких как буквы, знаки пунктуации, служебные знаки, пробелы и контрольные символы) в целые числа и затем непосредственно в биты. Каждый символ может быть закодирован уникальным двоичным кодом. Если вы плохо знакомы с концепцией битов, не волнуйтесь, мы вскоре о ней поговорим.

Группы символов выделяют в отдельные категории. Каждому символу соответствует кодовая точка, которую можно рассматривать просто как целое число. В таблице ASCII символы сегментированы следующим образом:

Диапазон кодовых точекКласс
от 0 до 31Контрольные и неотображаемые символы
от 32 до 64Знаки пунктуации, символы, числа и пробел
от 65 до 90Буквы английского алфавита в верхнем регистре
от 91 до 96Дополнительные графемы, такие как [ и \
от 97 до 122Буквы английского алфавита в нижнем регистре
от 123 до 126Дополнительные графемы, такие как { и |
127Контрольный неотображаемый символ (DEL)

Всего кодировка ASCII содержит 128 символов. В таблице ниже вы видите исчерпывающий набор знаков, которые позволяет отобразить эта кодировка. Если вы не видите какого-то символа, значит вы просто не сможете его вывести с помощью ASCII.

Кодовая точкаСимвол (имя)Кодовая точкаСимвол (имя)
0NUL (Null)64@
1SOH (Start of Heading)65A
2STX (Start of Text)66B
3ETX (End of Text)67C
4EOT (End of Transmission)68D
5ENQ (Enquiry)69E
6ACK (Acknowledgment)70F
7BEL (Bell)71G
8BS (Backspace)72H
9HT (Horizontal Tab)73I
10LF (Line Feed)74J
11VT (Vertical Tab)75K
12FF (Form Feed)76L
13CR (Carriage Return)77M
14SO (Shift Out)78N
15SI (Shift In)79O
16DLE (Data Link Escape)80P
17DC1 (Device Control 1)81Q
18DC2 (Device Control 2)82R
19DC3 (Device Control 3)83S
20DC4 (Device Control 4)84T
21NAK (Negative Acknowledgment)85U
22SYN (Synchronous Idle)86V
23ETB (End of Transmission Block)87W
24CAN (Cancel)88X
25EM (End of Medium)89Y
26SUB (Substitute)90Z
27ESC (Escape)91[
28FS (File Separator)92\
29GS (Group Separator)93]
30RS (Record Separator)94^
31US (Unit Separator)95_
32SP (Space)96`
33!97a
34"98b
35#99c
36$100d
37%101e
38&102f
39'103g
40(104h
41)105i
42*106j
43+107k
44,108l
45-109m
46. 110n
47/111o
480112p
491113q
502114r
513115s
524116t
535117u
546118v
557119w
568120x
579121y
58:122z
59;123{
60<124|
61=125}
62>126~
63?127DEL (delete)

Модуль string

Модуль string — простой и удобный инструмент, разграничивающий содержащиеся в ASCII символы по группам, разделяя их в строки-константы. _`{|}~»»»
printable = digits + ascii_letters + punctuation + whitespace

Большинство этих констант исчерпывающе описаны их идентификаторами. Мы вкратце коснёмся констант hexdigits и octdigits.

Мы можем использовать определённые в модуле константы для рутинных операций:

>>> import string

>>> s = "What's wrong with ASCII?!?!?"
>>> s.rstrip(string.punctuation)
'What's wrong with ASCII'

Прим. Обратите внимание, string.printable включает string.whitespace. Это несколько не соответствует тому, как печатаемые символы определяет метод str.isprintable(), который не рассматривает ни один из символов {'\v', '\n', '\r', '\f', '\t'} как печатаемый.

Это различие происходит из определения метода: str.isprintable() рассматривает что-либо печатаемым, если «все символы рассматриваются как печатаемые методом repr().

Что такое биты

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

Бит — это сигнал, который имеет два возможных состояния. Есть различные способы символического отображения этих состояний:

  • 0 или 1;
  • «да» или «нет»;
  • True или False;
  • «включено» или «выключено».

Таблица ASCII из предыдущего раздела использует то, что обычно назвали бы числами (от 0 до 127), однако для наших целей важно понимать, что это десятичные числа (с основанием 10).

Каждое из этих десятичных чисел можно выразить последовательностью бит (числом с основанием 2). Вот таблица соотношения двоичных и десятичных чисел:

ДесятичноеДвоичное (кратко)Двоичное (в байте)
0000000000
1100000001
21000000010
31100000011
410000000100
510100000101
611000000110
711100000111
8100000001000
9100100001001
10101000001010

Обратите внимание, что при увеличении десятичного числа n для его отображения (а следовательно и для отображения символа, относящегося к этому числу) требуется всё больше значимых бит.

Вот удобный метод представить строки ASCII как последовательность бит. Каждый символ из строки ASCII переводится в последовательность из 8 нолей и единиц с пробелами между этими последовательностями:

>>> def make_bitseq(s: str) -> str:
...     if not s.isascii():
...         raise ValueError("ASCII only allowed")
...     return " ".join(f"{ord(i):08b}" for i in s)

>>> make_bitseq("bits")
'01100010 01101001 01110100 01110011'

>>> make_bitseq("CAPS")
'01000011 01000001 01010000 01010011'

>>> make_bitseq("$25.43")
'00100100 00110010 00110101 00101110 00110100 00110011'

>>> make_bitseq("~5")
'01111110 00110101'

Прим. Обратите внимание, что метод .isascii() появился в Python 3.7.

Строковой литерал f-string f"{ord(i):08b}" использует мини-язык форматирования Format Specification Mini-Language, а именно его возможность замещения полей при форматировании строк.

  • левая часть выражения, ord(i), представляет объект, значение которого будет отформатировано и отображено при выводе. ord() возвращает кодовую точку одиночного символа str в десятичном выражении;
  • Правая сторона выражения определяет форматирование объекта. 08 означает ширина 8, заполнение нулями, а b работает как команда вывести число в двоичном (binary) эквиваленте.

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

Нам нужно больше бит

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

def n_possible_values(nbits: int) -> int:
    return 2 ** nbits

Вот что это означает:

  • 1 бит позволяет выразить 21 == 2 возможных значения;
  • 8 бит позволяют выразить 28 == 256 возможных значений;
  • 64 бита позволяют выразить 264 == 18 446 744 073 709 551 616 возможных значений.

В качестве естественного вывода из приведённой выше формулы мы можем установить следующее: для того, чтобы вычислить количество бит, необходимых для выражения определённого числа разных значений, нам нужно найти n в уравнении 2n=x, где переменная x известна.

Вот как можно это рассчитать:

>>> from math import ceil, log

>>> def n_bits_required(nvalues: int) -> int:
...     return ceil(log(nvalues) / log(2))

>>> n_bits_required(256)
8

Округление вверх в методе n_bits_required() требуется для расчёта значений, которые не являются чистой степенью двойки. К примеру, вам нужно сохранить набор из 110 различных символов. Для этого потребуется log(110) / log(2) == 6.781 бит, но поскольку бит для вычислительной техники является мельчайшей неделимой величиной, для отображения 110 различных значений нам понадобится 7 бит, при этом несколько значений останутся невостребованными.

>>> n_bits_required(110)
7

Всё сказанное служит для обоснования одной идеи: ASCII, строго говоря, семибитная кодировка. Эта таблица содержит 128 кодовых точек, и, соответственно, символов, от 0 до 127 включительно. Это требует 7 бит:

>>> n_bits_required(128)  # от 0 до 127
7
>>> n_possible_values(7)
128

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

Прим. В этой статье под байтом подразумевается группа из 8 бит, как повелось с 60-х годов прошлого века. Если вам не по душе это новомодное название, можете называть их октетами.

То, что ASCII-таблица использует 7 бит из доступных 8, означает, что память вычислительного устройства, занятого строками символов ASCII, наполовину пуста. Для того, чтобы лучше понять, почему это происходит, вернитесь к приведённой выше таблице соответствия двоичных и десятичных чисел. Вы можете выразить числа 0 и 1 с помощью 1 бита, или вы можете использовать 8 бит, чтобы выразить их как 00000000 и 00000001 соответственно.

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

Вы можете выразить числа от 0 до 3 всего двумя битами, от 00 до 11, или использовать 8 бит, чтобы выразить их как 00000000, 00000001, 00000010 и 00000011. Самая большая кодовая точка ASCII, 127, требует только 7 значимых бит.

С учётом этого взгляните, как метод make_bitseq() преобразует строки ASCII в строки, состоящие из байт, где каждый символ требует один байт:

>>> make_bitseq("bits")
'01100010 01101001 01110100 01110011'

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

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

Со временем появилась одна большая схема кодировки, которая объединила их. Однако, прежде чем мы до этого доберёмся, поговорим немного о краеугольных камнях схем кодировки символов — системах счисления.

Изучаем основы: другие системы счисления

В ASCII-таблице, как мы увидели, каждый символ соответствует числу от 0 до 127.

Этот диапазон чисел выражен в десятичной системе счисления. Именно эту систему используют для счёта люди, просто потому что на руках у нас по 10 пальцев.

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

Вопрос, какое число записано в строке "11" покажется странным, ведь для большинства очевидно, что это одиннадцать.

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

  • Двоичная: с основой 2;
  • Восьмеричная: с основой 8;
  • Шестнадцатеричная (hex): с основой 16.

Что же мы подразумеваем, говоря что определённая система счисления имеет основу N?

Один из способов объяснения разных систем счисления заключается в том, чтобы представить, что у вас N пальцев.

Если же вам требуется более подробное объяснение систем счисления, обратитесь к книге Чарльза Петцольда «Код». В этой книге детально объясняются основы работы вычислительной техники.

Конструктор int() — один из способов показать, как разные системы счисления преобразуют одну и ту же строку с помощью Python. Если вы передадите str в int(), Python по умолчанию будет считать, что строка содержит число в десятичной системе. Однако вы можете дать другие указания:

>>> int('11')
11
>>> int('11', base=10)  # 10 установлено по умолчанию
11
>>> int('11', base=2)  # Двоичная
3
>>> int('11', base=8)  # Восьмеричная
9
>>> int('11', base=16)  # Шестнадцатеричная
17

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

Тип литералаПрефиксПример
НетНет11
Binary literal0b или 0B0b11
Octal literal0o или 0O0o11
Hex literal0x или 0X0x11

Всё это — разновидности целочисленных литералов. Результаты применения префиксов будут такими же, как и в случае использования int() с определением параметра base. Для Python всё это просто целые числа:

>>> 11
11
>>> 0b11  # Двоичный литерал
3
>>> 0o11  # Восьмеричный литерал
9
>>> 0x11  # Шестнадцатеричный литерал
17

В таблице ниже отражено, как можно ввести десятичные числа от 0 до 20 в двоичном, восьмеричном и шестнадцатеричном эквиваленте. Любой из этих способов можно использовать как в оболочке интерпретатора Python, так и в исходном коде, и все эти числа будут рассматриваться как относящиеся к типу int.

ДесятичныеДвоичныеВосмеричныеШестнадцатеричные
00b00o00x0
10b10o10x1
20b100o20x2
30b110o30x3
40b1000o40x4
50b1010o50x5
60b1100o60x6
70b1110o70x7
80b10000o100x8
90b10010o110x9
100b10100o120xa
110b10110o130xb
120b11000o140xc
130b11010o150xd
140b11100o160xe
150b11110o170xf
160b100000o200x10
170b100010o210x11
180b100100o220x12
190b100110o230x13
200b101000o240x14

Кстати, вы можете сами убедиться, что подобные способы записи чисел очень часто используется в Стандартной Библиотеке Python. Найдите папку lib/python3.7/ в своей системе, перейдите в неё и введите команду:

$ grep -nri --include "*\.py" -e "\b0x" lib/python3.7

Команда сработает в любой Unix-системе с утилитой grep. С её помощью вы найдёте все шестнадцатеричные литералы. Для поиска двоичных используйте \b0b, а для восьмеричных — \b0o.

Для чего же нужны альтернативные литералы целых чисел? Если коротко, числа 2, 8 и 16, в отличие от 10, являются степенями двойки. Основанные на них системы счисления выражают численные значения способами, более удобными для обработки бинарными вычислительными устройствами. К примеру, 65536, или 216, в шестнадцатеричной системе просто 10000 или, используя литерал, 0x10000.

Введение в Юникод

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

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

Вы можете представить Юникод как расширенную версию ASCII-таблицы — с 1 114 112 возможными кодовыми точками, от 0 до 1 114 111. Это 17*(216) или 0x10ffff в шестнадцатеричном представлении. Фактически, ASCII является частью Юникода, так как первые 128 символов этих кодировок полностью совпадают.

Чтобы соблюсти технические детали, сам по себе Юникод не является кодировкой. Он скорее реализуется в различных кодировках символов, как вы вскоре увидите. По структуре Юникод скорее ассоциативный массив (что-то вроде dict) или база данных, состоящая из таблицы с двумя колонками. В этой таблице разные символы (такие как "a""¢", или даже "ቈ") соотносятся с различными целыми положительными числами. Кодировка же должна предоставлять несколько больше возможностей.

Юникод содержит практически любой символ, который только можно представить, включая дополнительные непечатаемые. Например, кодовая точка 8207 соответствует отметке RTL, которая используется для смены направления письма. Она полезна в текстах, где абзацы на одном из европейских языков соседствуют с абзацами на арабских языках.

Прим. Кстати, если уж мы хотим быть совсем точны в деталях, то надо отметить ещё один факт. Исторически сложилось, что в Юникоде доступны только 1 111 998 кодовых точек.

Юникод и UTF-8

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

Ранее мы упоминали, что Юникод сам по себе не является кодировкой. И вот почему.

Юникод не содержит указаний по извлечению из текста бит, он работает только с кодовыми точками. В нём нет стандарта конверсии текста в двоичные данные и обратно.

Юникод является абстрактным стандартом кодировки. Для практического его применения чаще всего используют схему UTF-8. Стандарт Юникод (таблица соответствий символов кодовыми точкам) определяет несколько различных кодировок на основе единого набора символов.

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

Сначала требуется разобрать термины «‎‎кодирование»‎ и «‎декодирование»‎.

Кодирование и декодирование в Python 3

Тип данных str в Python 3 рассчитан на представление текста в удобном для чтения формате и может содержать любые символы Юникода.

Тип bytes, напротив, представляет двоичные данные, последовательность байт, без указания на кодировку.

Кодирование и декодирование — это процесс перехода данных из одной формы в другую.

В методах .encode() и .decode() по умолчанию используется параметр "utf-8", однако для большей уверенности этот параметр можно определить самостоятельно:

>>> "résumé".encode("utf-8")
b'r\xc3\xa9sum\xc3\xa9'
>>> "El Niño".encode("utf-8")
b'El Ni\xc3\xb1o'

>>> b"r\xc3\xa9sum\xc3\xa9".decode("utf-8")
'résumé'
>>> b"El Ni\xc3\xb1o".decode("utf-8")
'El Niño'

str.encode() возвращает объект типа bytes. И литералы этого типа объектов (такие как b"r\xc3\xa9sum\xc3\xa9"), и его отображение допускают только символы ASCII.

Вот почему при вызове "El Niño".encode("utf-8"), ASCII-совместимое "El" отображается как есть, а n с тильдой экранируется в "\xc3\xb1". Этой с виду неудобочитаемой последовательностью представлены два байта, 0xc3 и 0xb1 в шестнадцатеричной системе:

>>> " ".join(f"{i:08b}" for i in (0xc3, 0xb1))
'11000011 10110001'

Таким образом символ ñ требует два байта для бинарного представления с помощью UTF-8.

Прим. Если вы введёте help(str.encode), скорее всего, увидите параметр по умолчанию encoding='utf-8'. Однако имейте в виду, что настройки Windows для Python 3.6 могут отличаться, поэтому использовать методы кодирования и декодирования без указания необходимой кодировки (например "résumé".encode()) следует с осторожностью.

Python 3: всё на Юникоде

Python 3 полностью реализован на Юникоде, а точнее на UTF-8. Вот что это означает:

  • По умолчанию предполагается, что исходный код Python 3 написан с помощью UTF-8. Это значит, что вам не нужно использовать определение # -*- coding: UTF-8 -*- в начале файлов .py в этой версии языка.
  • Все тексты (объекты формата str) реализованы на Юникоде. Кодированный текст представлен двоичными данными (bytes). Тип strможет содержать любой символ-литерал из Юникода (например "Δv / Δt"), и все они хранятся в Юникоде.
  • Любой из символов Юникода приемлем в качестве идентификатора. Например, вы можете использовать выражение résumé = "~/Documents/resume.pdf".
  • В модуле re по умолчанию установлен флаг re.UNICODE, а не re.ASCII. Это означает, что r"\w" соответствует буквам из Юникода, а не просто символам ASCII.
  • По умолчаниюencoding в str.encode() в bytes.decode() установлен в UTF-8.

Нужно отметить также нюанс, касающийся встроенного метода open(). Его параметр encoding зависит от платформы и определяется значением locale.getpreferredencoding():

>>> # Mac OS X High Sierra
>>> import locale
>>> locale.getpreferredencoding()
'UTF-8'

>>> # Windows Server 2012; другие сборки Windows могут использовать UTF-16
>>> import locale
>>> locale.getpreferredencoding()
'cp1252'

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

Один байт, два байта, три байта, четыре…

Одна из важнейших особенностей UTF-8 состоит в том, что это кодировка с переменным размером.

Вспомните раздел, посвящённый ASCII. Любой символ в этой таблице требует максимум одного байта пространства. Это можно быстро проверить с помощью следующего генератора:

>>> all(len(chr(i).encode("ascii")) == 1 for i in range(128))
True

С UTF-8 дела обстоят по-другому. Символы Юникода могут занимать от одного до четырёх байт. Вот пример четырёхбайтного символа:

>>> ibrow = "🤨"
>>> len(ibrow)
1
>>> ibrow.encode("utf-8")
b'\xf0\x9f\xa4\xa8'
>>> len(ibrow.encode("utf-8"))
4

>>> # Вызов list() с объектом типа bytes возвращает
>>> # значение каждого байта
>>> list(b'\xf0\x9f\xa4\xa8')
[240, 159, 164, 168]

Это небольшая, но важная особенность метода len():

  • Размер единичного символа Юникода в объекте str языка Python всегда будет равен 1, вне зависимости от количества занимаемых байт.
  • Длина того же символа в объекте типа bytes будет варьироваться от 1 до 4.

Таблица ниже показывает, сколько байт занимают основные типы символов.

Десятичный диапазонШестнадцатеричный
диапазон
Включённые символыПримеры
от 0 до 127от "\u0000" до "\u007F"U.S. ASCII"A""\n""7""&"
от 128 до 2047от "\u0080" до "\u07FF"Большая часть латинских алфавитов*"ę""±""ƌ""ñ"
от 2048 до 65535от "\u0800" до "\uFFFF"Дополнительные части многоязыковых символов (BMP)**"ത""ᄇ""ᮈ""‰"
от 65536 до 1114111от "\U00010000" до "\U0010FFFF"Другое***"𝕂""𐀀""😓""🂲",

*Такие как английский, арабский, греческий, ирландский.
**Масса языков и символов, в основном китайский, японский и корейский с разделением по томам (а также ASCII и латиница).
***Дополнительные символы китайского, японского, корейского и вьетнамского, а также другие символы и эмоджи.

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

Особенности UTF-16 и UTF-32

Рассмотрим альтернативные кодировки, UTF-16 и UTF-32. Различие между ними и UTF-8 в основном практическое. Продемонстрируем величину расхождения с помощью перевода туда и обратно:

>>> letters = "αβγδ"
>>> rawdata = letters.encode("utf-8")
>>> rawdata.decode("utf-8")
'αβγδ'
>>> rawdata.decode("utf-16")  # 😧
'뇎닎돎듎'

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

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

Таблица ниже демонстрирует количество байт, используемых в разных кодировках:

КодировкаБайт на символ (включительно)Варьируемая длина
UTF-8От 1 до 4Да
UTF-16От 2 до 4Да
UTF-324Нет

Любопытный аспект семейства UTF: UTF-8 не всегда занимает меньше памяти, чем UTF-16. Хотя с точки зрения математики это выглядит маловероятным, однако это возможно:

>>> text = "記者 鄭啟源 羅智堅"
>>> len(text.encode("utf-8"))
26
>>> len(text.encode("utf-16"))
22

Так получается из-за того, что кодовые точки в диапазоне от U+0800 до U+FFFF (от 2048 до 65535 в десятичной системе) в кодировке UTF-8 занимают три байта, а в UTF-16 только два.

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

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

Прим. перев. Есть и более весомые причины использовать UTF-8. Среди них её обратная совместимость с ASCII, а также то, что это самосинхронизирующаяся кодировка.

Python и встроенные функции

Вы освоили самую сложную часть статьи. Теперь посмотрим, как всё изученное реализуется на Python.

В Python есть несколько встроенных функций, каким-либо образом относящихся к системам счисления и кодировке:

Логически их можно сгруппировать по назначению.

  • ascii()bin()hex() и oct() предназначены для различного представления вводных данных. Все они возвращают str. Первая, ascii(), производит представление объекта в ASCII, экранируя не входящие в эту таблицу символы. Оставшиеся три дают соответственно двоичное, шестнадцатеричное и восьмеричное представление целого числа. Все эти функции меняют только представление объекта, не изменяя непосредственно вводные данные.
  • bytes()str() и int() — конструкторы классов соответствующих типов: bytesstr, и int. Все они предлагают способы подогнать данные под желаемый тип.
  • ord() и chr() выполняют противоположные действия. ord() конвертирует символ в десятичную кодовую точку, а chr() принимает в качестве аргумента целое число, и возвращает символ, кодовой точкой которого это число является.

В таблице ниже эти функции разобраны более подробно:

ФункцияФормаТип аргументовТип возвращаемых данныхНазначение
ascii()ascii(obj)РазличныйstrПредставление объекта символами ASCII. Не входящие в таблицу символы экранируются
bin()bin(number)number: intstrБинарное представление целого чиста с префиксом "0b"
bytes()bytes(последовательность_целых_чисел)

bytes(s, enc[, errors])

bytes(байты_или_буфер)

bytes([i])

РазличныйbytesПриводит аргумент к двоичным данным, типу bytes
chr()chr(i)i: int

i>=0

i<=1114111

strПреобразует кодовую точку (целочисленное значение) в символ Юникода
hex()hex(number)number: intstrШестнадцатеричное представление целого числа с префиксом "0x"
int()int([x])

int(x, base=10)

РазличныйintПриводит аргумент к типу int
oct()oct(number)number: intstrВосьмеричное представление целого числа с префиксом "0o"
ord()ord(c)c: str

len(c) == 1

intВозвращает значение кодовой точки символа Юникода
str()str(object=’‘)

str(b[, enc[, errors]])

РазличныйstrПриводит аргумент к текстовому представлению, типу str

Дальше можно посмотреть полезные примеры использования этих функций.

ascii():

>>> ascii("abcdefg")
"'abcdefg'"

>>> ascii("jalepeño")
"'jalepe\\xf1o'"

>>> ascii((1, 2, 3))
'(1, 2, 3)'

>>> ascii(0xc0ffee)  # Шестнадцатеричный литерал (int)
'12648430'

bin():

>>> bin(0)
'0b0'

>>> bin(400)
'0b110010000'

>>> bin(0xc0ffee)  # Шестнадцатеричный литерал (int)
'0b110000001111111111101110'

>>> [bin(i) for i in [1, 2, 4, 8, 16]]  # `int` + обработка списка
['0b1', '0b10', '0b100', '0b1000', '0b10000']

bytes():

>>> # Последовательность целых чисел
>>> bytes((104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100))
b'hello world'

>>> bytes(range(97, 123))  # Последовательность целых чисел
b'abcdefghijklmnopqrstuvwxyz'

>>> bytes("real 🐍", "utf-8")  # Строка + кодировка
b'real \xf0\x9f\x90\x8d'

>>> bytes(10)
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

>>> bytes.fromhex('c0 ff ee')
b'\xc0\xff\xee'

>>> bytes.fromhex("72 65 61 6c 70 79 74 68 6f 6e")
b'realpython'

chr():

>>> chr(97)
'a'

>>> chr(7048)
'ᮈ'

>>> chr(1114111)
'\U0010ffff'

>>> chr(0x10FFFF)  # Шестнадцатеричный литерал (int)
'\U0010ffff'

>>> chr(0b01100100)  # Двоичный литерал (int)
'd'

hex():

>>> hex(100)
'0x64'

>>> [hex(i) for i in [1, 2, 4, 8, 16]]
['0x1', '0x2', '0x4', '0x8', '0x10']

>>> [hex(i) for i in range(16)]
['0x0', '0x1', '0x2', '0x3', '0x4', '0x5', '0x6', '0x7',
 '0x8', '0x9', '0xa', '0xb', '0xc', '0xd', '0xe', '0xf']

int():

>>> int(11.0)
11

>>> int('11')
11

>>> int('11', base=2)
3

>>> int('11', base=8)
9

>>> int('11', base=16)
17

>>> int(0xc0ffee - 1.0)
12648429

>>> int.from_bytes(b"\x0f", "little")
15

>>> int.from_bytes(b'\xc0\xff\xee', "big")
12648430

oct():

>>> ord("a")
97

>>> ord("ę")
281

>>> ord("ᮈ")
7048

>>> [ord(i) for i in "hello world"]
[104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]

str():

>>> str("str of string")
'str of string'

>>> str(5)
'5'

>>> str([1, 2, 3, 4])  # Like [1, 2, 3, 4].__str__(), but use str()
'[1, 2, 3, 4]'

>>> str(b"\xc2\xbc cup of flour", "utf-8")
'¼ cup of flour'

>>> str(0xc0ffee)
'12648430'

Литералы для строк на Python

Вместо использования конструктора str(), объект этого типа чаще вводят напрямую:

>>> meal = "shrimp and grits"

Выглядит достаточно просто. Но есть один аспект, о котором нужно помнить. Поскольку Python позволяет использовать все возможности Юникода, можно «напечатать» символы, которых вы никогда не найдёте на клавиатуре. Можно скопировать и вставить их прямо в оболочку интерпретатора:

>>> alphabet = 'αβγδεζηθικλμνξοπρςστυφχψ'
>>> print(alphabet)
αβγδεζηθικλμνξοπρςστυφχψ

Кроме ввода через консоль реальных, неэкранированых символов Юникода, существуют и другие способы ввода текстовых строк.

Самые насыщенные разделы документации Python посвящены лексическому анализу. В частности, раздел о строках и литералах. Возможно, для понимания данного аспекта языка этот раздел придётся неоднократно перечитать.

Кроме прочего, там говорится о шести возможных способах ввода одного символа Юникода.

Первый, и самый распространённый метод, как вы уже видели — прямой ввод. Проблема состоит в поиске необходимых сочетаний клавиш. Здесь и могут пригодиться другие способы получения и представления символов. Вот полный список:

Экранирующая последовательностьЗначениеКак отобразить "a"
"\ooo"Символ с восьмеричным значением ooo"\141"
"\xhh"Символ с шестнадцатеричным значением hh"\x61"
"\N{name}"Символ с именем name в базе данных Юникода"\N{LATIN SMALL LETTER A}"
"\uxxxx"Символ с шестнадцатибитным (двухбайтным) шестнадцатеричным значением xxxx"\u0061"
"\Uxxxxxxxx"Символ с тридцатидвухбитным (четырёхбайтным) шестнадцатеричным значением xxxxxxxx"\U00000061"

Это соответствие можно проверить на практике:

>>> (
...     "a" ==
...     "\x61" == 
...     "\N{LATIN SMALL LETTER A}" ==
...     "\u0061" ==
...     "\U00000061"
... )
True

Нужно однако упомянуть и два основных затруднения при использовании этих методов:

  1. Не каждый способ работает со всеми символами. Шестнадцатеричное представление числа 300 выглядит как 0x012c, а это значение просто не поместится в экранирующий код "\xhh", так как в нём допускаются всего две цифры. Самая большая кодовая точка, которую можно втиснуть в этот формат — "\xff" ("ÿ"). Аналогичо "\ooo" можно использовать только до "\777" ("ǿ").
  2. Для \xhh\uxxxx, и \Uxxxxxxxx требуется вводить ровно столько цифр, сколько указано в примерах. Это может стать неприятным сюрпризом, поскольку обычно основанные на Юникоде таблицы содержат кодовые точки для символов с префиксом U+ и варьирующимся количеством шестнадцатеричных символов. В этих таблицах кодовые точки отображают только значимые цифры.

Например, если вы обратитесь к сайту unicode-table.com с целью получить данные готического символа faihu (или fehu), "𐍆", его кодовая точка будет U+10346.

Как же можно разместить его в "\uxxxx" или "\Uxxxxxxxx"? В "\uxxxx" эту кодовую точку вместить невозможно, поскольку она соответствует четырёхбайтному символу. А чтобы представить его в "\Uxxxxxxxx", придётся выровнять последовательность с левой стороны:

>>> "\U00010346"
'𐍆'

Это также значит, что экранирующая последовательность "\Uxxxxxxxx" — единственная последовательность, способная вместить любой символ Юникода.

Прим. Вот код небольшой, но удобной функции, переводящей записи типа "U+10346" в приемлемый для Python формат с помощью str.zfill():

>>> def make_uchr(code: str):
...     return chr(int(code.lstrip("U+").zfill(8), 16))
>>> make_uchr("U+10346")
'𐍆'
>>> make_uchr("U+0026")
'&'

Другие поддерживаемые Python кодировки

Пока что мы рассказали про 4 разные кодировки символов:

  1. ASCII;
  2. UTF-8;
  3. UTF-16;
  4. UTF-32.

Однако существует большое количество и других вариантов кодировки.

Один из примеров — Latin-1 (другое название ISO-8859-1). Это базовая кодировка для Hypertext Transfer Protocol (HTTP) в спецификации RFC 2616. Для Windows существует собственный вариант Latin-1, который называется cp1252.

Прим. Кодировка ISO-8859-1 всё ещё широко используется. Библиотека requests неукоснительно придерживается спецификации RFC 2616, используя её по умолчанию для содержимого отзывов HTTP/HTTPS. Если в заголовке Content-Type находится слово «text» и не выбрана другая кодировка, requests использует ISO-8859-1.

Полный список допустимых кодировок можно найти в документации модуля codecs, входящего в набор стандартных библиотек Python.

Среди этих кодировок стоит упомянуть ещё одну, зачастую весьма полезную. Это "unicode-escape". Если вы декодировали str и хотите быстро получить представление содержащихся в ней экранированных литералов Юникода, можно определить эту кодировку в .encode:

>>> alef = chr(1575)  # Или "\u0627"
>>> alef_hamza = chr(1571)  # Или "\u0623"
>>> alef, alef_hamza
('ا', 'أ')
>>> alef.encode("unicode-escape")
b'\\u0627'
>>> alef_hamza.encode("unicode-escape")
b'\\u0623'

Вы знаете, что говорят насчёт предположений…

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

Когда вы получаете данные в двоичном коде из внешних источников, из файла или по сетевому соединению, стоит проверить, указана ли кодировка. Если нет — вы можете уточнить.

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

Приведём пример того, что может пойти не так. Допустим, вы подписаны на API, который передаёт вам рецепт блюда дня. Вы получаете его в формате bytes и раньше всегда без проблем декодировали с использованием .decode("utf-8") . Но именно в этот день часть рецепта выглядела так:

>>> data = b"\xbc cup of flour"

Похоже, нам потребуется мука, но сколько?

>>> data.decode("utf-8")
Traceback (most recent call last):
  File "", line 1, in 
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbc in position 0: invalid start byte

А вот и та самая неприятная ошибка UnicodeDecodeError. Подобное вполне может произойти, когда вы делаете предположение об используемой кодировке. Уточняем у разработчика ресурса, предоставляющего API. Выясняется, что полученный вами файл был закодирован с помощью  Latin-1:

>>> data.decode("latin-1")
'¼ cup of flour'

Именно в этом и крылась проблема. В Latin-1 каждый символ кодируется одним байтом, в вот в UTF-8 символ «¼» требует два байта ("\xc2\xbc").

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

Если уж у вас нет другого выхода и кодировку приходится угадывать, обратите внимание на библиотеку chardet. В ней используются разработанные в Mozilla методы, позволяющие сделать обоснованное предположение насчёт кодировки данных. Однако учтите, что такие инструменты должны быть вашим последним средством, не стоит прибегать к ним, если есть возможность решить вопрос другим способом.

Всякая всячина: unicodedata

Нельзя не упомянуть также модуль unicodedata. Он позволяет взаимодействовать с базой данных символов Юникода (Unicode Character Database, UCD).

>>> import unicodedata

>>> unicodedata.name("€")
'EURO SIGN'
>>> unicodedata.lookup("EURO SIGN")
'€'

Подводим итоги

Итак, в этой статье вы познакомились со следующими концепциями кодировки символов в Python:

  • Фундаментальные принципы кодировки символов и систем счисления;
  • Целочисленные, двоичные, восьмеричные, шестнадцатеричные, строковые и байтовые литералы в Python;
  • Встроенные функции языка, работающие с кодировкой и системами счисления;
  • Особенности обработки текстовых и двоичных данных.

Дополнительные источники

Ещё больше информации можно получить из следующих материалов (на английском языке):

  • UTF-8 Everywhere Manifesto.
  • Joel Spolsky: Минимальный уровень знаний о Юникоде и наборах символов, требующийся каждому разработчику ПО (Без отговорок!). 
  • David Zentgraf: Что обязательно должен знать о кодировках и наборах символов каждый программист для работы с текстом. 
  • Mozilla: Комплексный подход к определению языков и кодировок.
  • Wikipedia.
  • John Skeet: Юникод и .NET.
  • Network Working Group, RFC 3629: UTF-8, формат преобразования ISO 10646.
  • Unicode Technical Standard #18: Регулярные выражения Юникода.

В документации языка нашему вопросу посвящены два раздела:

Перевод статьи Unicode & Character Encodings in Python: A Painless Guide

Что такое кодировка UTF-8? Руководство для непрограммистов

Текст: его важность в Интернете само собой разумеется. Это первая буква «Т» в «HTTP», единственная буква «Т» в «HTML», и практически каждый веб-сайт так или иначе использует ее, будь то URL-адрес, часть маркетингового текста, обзор продукта, вирусный твит или Сообщение блога. (Привет!)

Но веб-текст на самом деле может быть не таким простым, как вы думаете. Рассмотрим тысячи языков, на которых сегодня говорят, или все знаки препинания и символы, которые мы можем добавить, чтобы улучшить их, или тот факт, что создаются новые смайлики, чтобы уловить каждую человеческую эмоцию.Как веб-сайты все это хранят и обрабатывают?

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

Прежде чем мы начнем, вы должны быть знакомы с основами HTML и готовы погрузиться в легкую информатику.

Что такое UTF-8?

UTF-8 означает «Формат преобразования Unicode — 8 бит». Пока это нам не помогает, так что давайте вернемся к основам.

Двоичный: как компьютеры хранят информацию

Для хранения информации компьютеры используют двоичную систему. В двоичном формате все данные представлены последовательностями из единиц и нулей. Самая основная единица двоичного кода — это бит , который представляет собой всего лишь единицу 1 или 0. Следующая по величине единица двоичного кода, байт, состоит из 8 бит.Пример байта — «01101011».

Каждый цифровой актив, с которым вы когда-либо сталкивались — от программного обеспечения до мобильных приложений, от веб-сайтов до историй в Instagram — построен на этой системе байтов, которые связаны друг с другом таким образом, чтобы они имели смысл для компьютеров. Когда мы говорим о размерах файлов, мы имеем в виду количество байтов. Например, килобайт — это примерно тысяча байт, а гигабайт — примерно миллиард байтов.

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

ASCII: преобразование символов в двоичные

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

Библиотека

ASCII включает все прописные и строчные буквы латинского алфавита (A, B, C…), каждую цифру от 0 до 9 и некоторые общие символы (например, /,! И?). Он присваивает каждому из этих символов уникальный трехзначный код и уникальный байт.

В таблице ниже показаны примеры символов ASCII с соответствующими кодами и байтами.

Знак Код ASCII БАЙТ
А 065 01000001
a 097 01100001
B 066 01000010
б 098 01100010
Z 090 01011010
z 122 01111010
0 048 00110000
9 057 00111001
! 033 00100001
? 063 00111111

Подобно тому, как символы объединяются для образования слов и предложений на языке, двоичный код делает это в текстовых файлах.Итак, фраза «Быстрая коричневая лисица перепрыгивает через ленивого пса». в двоичном формате ASCII будет:

 
 

01010100 01101000 01100101 00100000 01110001

01110101 01101001 01100011 01101011 00100000

01100010 01110010 01101111 01110111 01101110

00100000 01100110 01101111 01111000 00100000

01101010 01110101 01101101 01110000 01110011

00100000 01101111 01110110 01100101 01110010

00100000 01110100 01101000 01100101 00100000

01101100 01100001 01111010 01111001 00100000

01100100 01101111 01100111 00101110

Это мало что значит для нас, людей, но это хлеб с маслом для компьютера.

Число символов, которые может представлять ASCII, ограничено числом доступных уникальных байтов, поскольку каждый символ получает один байт. Если вы посчитаете, то обнаружите, что существует 256 различных способов сгруппировать восемь единиц и нулей вместе. Это дает нам 256 различных байтов или 256 способов представления символа в ASCII. Когда в 1960 году был представлен ASCII, это было нормально, поскольку разработчикам требовалось всего 128 байт для представления всех необходимых им английских символов и символов.

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

Unicode: способ сохранить каждый символ, когда-либо

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

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

Ниже приведены несколько примеров текстовых символов и соответствующих им кодовых точек. Каждая кодовая точка начинается с буквы «U» для «Unicode», за которой следует уникальная строка символов для представления символа.

Знак Кодовая точка
А U + 0041
a U + 0061
0 U + 0030
9 U + 0039
! U + 0021
Ø U + 00D8
ڃ U + 0683
U + 0C9A
𠜎 U + 2070E
😁 U + 1F601

Если вы хотите узнать, как генерируются кодовые точки и что они означают в Unicode, ознакомьтесь с этим подробным объяснением.

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

Но только Unicode не хранит слова в двоичном формате. Компьютерам нужен способ перевода Unicode в двоичный код, чтобы его символы можно было хранить в текстовых файлах. Вот где пригодится UTF-8.

UTF-8: последний фрагмент головоломки

UTF-8 — это система кодирования Unicode.Он может преобразовать любой символ Юникода в соответствующую уникальную двоичную строку, а также может преобразовать двоичную строку обратно в символ Юникода. Это значение «UTF» или «Формат преобразования Unicode».

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

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

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

Знак Кодовая точка Двоичная кодировка UTF-8
А U + 0041 01000001
a U + 0061 01100001
0 U + 0030 00110000
9 U + 0039 00111001
! U + 0021 00100001
Ø U + 00D8 11000011 10011000
ڃ U + 0683 11011010 10000011
U + 0C9A 11100000 10110010 10011010
𠜎 U + 2070E 11110000 10100000 10011100 10001110
😁 U + 1F601 11110000 10011111 10011000 10000001

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

Пространственная эффективность — ключевое преимущество кодировки UTF-8. Если бы вместо этого каждый символ Unicode был представлен четырьмя байтами, текстовый файл, написанный на английском языке, был бы в четыре раза больше, чем тот же файл, закодированный с помощью UTF-8.

Еще одним преимуществом кодировки UTF-8 является ее обратная совместимость с ASCII. Первые 128 символов в библиотеке Unicode соответствуют символам в библиотеке ASCII, а UTF-8 переводит эти 128 символов Unicode в те же двоичные строки, что и ASCII. В результате UTF-8 может без проблем принимать текстовый файл, отформатированный с помощью ASCII, и преобразовывать его в читаемый человеком текст.

Символы UTF-8 в веб-разработке

UTF-8 — наиболее распространенный метод кодировки символов, используемый сегодня в Интернете, и набор символов по умолчанию для HTML5.Более 95% всех веб-сайтов, в том числе и ваш собственный, хранят персонажей таким образом. Кроме того, распространенные методы передачи данных через Интернет, такие как XML и JSON, кодируются стандартами UTF-8.

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

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

 
 

Это сообщает браузеру, что файл HTML закодирован в UTF-8, чтобы браузер мог преобразовать его обратно в разборчивый текст.

UTF-8 против UTF-16

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

Это различие видно из их названий. В UTF-8 наименьшее двоичное представление символа — это один байт или восемь битов. В UTF-16 наименьшее двоичное представление символа составляет два байта или шестнадцать бит.

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

Знак Двоичная кодировка UTF-8 Двоичная кодировка UTF-16
А 01000001 01000001 11011000 00001110 11011111
𠜎 11110000 10100000 10011100 10001110 01000001 11011000 00001110 11011111

Кодировка

UTF-8 предпочтительнее UTF-16 на большинстве веб-сайтов, поскольку она использует меньше памяти.Напомним, что UTF-8 кодирует каждый символ ASCII всего одним байтом. UTF-16 должен кодировать эти же символы в двух или четырех байтах. Это означает, что текстовый файл на английском языке с кодировкой UTF-16 будет как минимум в два раза больше размера того же файла с кодировкой UTF-8.

UTF-16 более эффективен, чем UTF-8, только на некоторых неанглоязычных сайтах. Если веб-сайт использует язык с символами, находящимися дальше в библиотеке Unicode, UTF-8 будет кодировать все символы как четыре байта, тогда как UTF-16 может кодировать многие из тех же символов только как два байта.Тем не менее, если ваши страницы заполнены буквами ABC и 123, придерживайтесь UTF-8.

Расшифровка мира кодировки UTF-8

Это было много слов о словах, поэтому давайте резюмируем то, что мы рассмотрели:

  1. Компьютеры хранят данные, включая текстовые символы, как двоичные (единицы и нули).
  2. ASCII был ранним способом кодирования или отображения символов в двоичный код, чтобы компьютеры могли их хранить. Однако в ASCII не было достаточно места для представления нелатинских символов и чисел в двоичном формате.
  3. Unicode был решением этой проблемы. Unicode присваивает уникальный «код» каждому символу на каждом человеческом языке.
  4. UTF-8 — это метод кодировки символов Юникода. Это означает, что UTF-8 берет кодовую точку для данного символа Юникода и переводит ее в строку двоичного кода. Он также делает обратное, считывая двоичные цифры и преобразуя их обратно в символы.
  5. UTF-8 в настоящее время является самым популярным методом кодирования в Интернете, поскольку он может эффективно хранить текст, содержащий любые символы.
  6. UTF-16 — еще один метод кодирования, но он менее эффективен для хранения текстовых файлов (за исключением тех, которые написаны на некоторых неанглийских языках).

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

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

Кодировка строки Python ()

Начиная с Python 3.0, строки хранятся как Unicode, т.е. каждый символ в строке представлен кодовой точкой. Итак, каждая строка — это просто последовательность кодовых точек Unicode.

Для эффективного хранения этих строк последовательность кодовых точек преобразуется в набор байтов. Этот процесс известен как encoding .

Существуют различные кодировки, которые по-разному обрабатывают строку. Популярные кодировки: utf-8 , ascii и т. Д.

Используя метод строки encode () , вы можете преобразовать некодированные строки в любые кодировки, поддерживаемые Python. По умолчанию Python использует кодировку utf-8 .


Синтаксис метода encode () :

string.encode (кодировка = 'UTF-8', errors = 'strict') 

String encode () Параметры

По умолчанию метод encode () не требует никаких параметров.

Возвращает версию строки в кодировке utf-8.В случае сбоя возникает исключение UnicodeDecodeError .

Однако он принимает два параметра:

  • кодировка — тип кодировки, в котором строка должна быть закодирована в
  • ошибок — ответ при сбое кодирования. Есть шесть типов реакции на ошибку
    • strict — ответ по умолчанию, который вызывает исключение UnicodeDecodeError при сбое
    • ignore — игнорирует некодируемый юникод из результата
    • replace — заменяет некодируемый юникод на вопросительный знак ?
    • xmlcharrefreplace — вставляет ссылку на символ XML вместо некодируемого юникода
    • backslashreplace — вставляет escape-последовательность \ uNNNN вместо некодируемого юникода
    • namereplace — вставляет \ N {…} escape-последовательность вместо некодируемого юникода

Пример 1: Кодирование по умолчанию Utf-8 Кодировка

  # строка Unicode
строка = 'pythön!'

# напечатать строку
print ('Строка:', строка)

# кодировка по умолчанию в utf-8
строка_utf = строка.encode ()

# результат печати
print ('Закодированная версия:', string_utf) 
 

Выход

  Строка: pythön!
Закодированная версия: b'pyth \ xc3 \ xb6n! ' 
 

Пример 2: Кодирование с параметром ошибки

  # строка Unicode
строка = 'pythön!'

# напечатать строку
print ('Строка:', строка)

# игнорировать ошибку
print ('Закодированная версия (с игнорированием):', string.encode ("ascii", "игнорировать"))

# заменить ошибку
print ('Закодированная версия (с заменой):', string.encode ("ascii", "replace")) 
 

Выход

  Строка: pythön!
Закодированная версия (с игнорированием): b'pythn! '
Закодированная версия (с заменой): b'pyth? N! ' 
 

Примечание: Попробуйте также другие параметры кодировки и ошибок.

utf8 — язык программирования Go

Обзор ▹

Обзор ▾

Пакет utf8 реализует функции и константы для поддержки текста, закодированного в
UTF-8.Он включает функции для перевода между рунами и последовательностями байтов UTF-8.
См. Https://en.wikipedia.org/wiki/UTF-8.

Константы

Числа, необходимые для кодирования.

 const (
    RuneError = '\ uFFFD'
    RuneSelf = 0x80
    MaxRune = '\ U0010FFFF'
    UTFMax = 4
) 
 func DecodeLastRune (p [] byte) (r rune, size int) 

DecodeLastRune распаковывает последнюю кодировку UTF-8 в p и возвращает руну и
его ширина в байтах.Если p пусто, возвращается (RuneError, 0). В противном случае, если
кодировка недействительна, возвращается (RuneError, 1). Оба невозможны
результаты для правильного непустого UTF-8.

Кодировка недействительна, если это неверный UTF-8, кодирует руну, которая
вне диапазона или не является самой короткой кодировкой UTF-8 для
значение. Никакая другая проверка не выполняется.

▾ Пример

основной пакет

Импортировать (
«fmt»
«Юникод / ​​UTF8»
)

func main () {
b: = [] байт («Привет,»)

for len (b)> 0 {
r, размер: = utf8.DecodeLastRune (b)
fmt.Printf («% c% v \ n», r, размер)

b = b [: len (b) -размер]
}
}

 界 3
世 3
  1
, 1
o 1
l 1
l 1
e 1
H 1
 

Запустить
Формат

доля

 func DecodeLastRuneInString (s строка) (r руна, размер int) 

DecodeLastRuneInString похож на DecodeLastRune, но его ввод — это строка. Если
s пусто, он возвращает (RuneError, 0). В противном случае, если кодировка недействительна,
он возвращает (RuneError, 1).Оба результата невозможны для правильного,
непустой UTF-8.

Кодировка недействительна, если это неверный UTF-8, кодирует руну, которая
вне диапазона или не является самой короткой кодировкой UTF-8 для
значение. Никакая другая проверка не выполняется.

▾ Пример

основной пакет

Импортировать (
«fmt»
«Юникод / ​​UTF8»
)

func main () {
str: = «Привет, 世界»

for len (str)> 0 {
r, размер: = utf8.DecodeLastRuneInString (str)
fmt.Printf («% c% v \ n», r, размер)

str = str [: len (str) -size]
}
}

 界 3
世 3
  1
, 1
o 1
l 1
l 1
e 1
H 1
 

Запустить
Формат

доля

 func DecodeRune (p [] byte) (r rune, size int) 

DecodeRune распаковывает первую кодировку UTF-8 в p и возвращает руну и
его ширина в байтах.Если p пусто, возвращается (RuneError, 0). В противном случае, если
кодировка недействительна, возвращается (RuneError, 1). Оба невозможны
результаты для правильного непустого UTF-8.

Кодировка недействительна, если это неверный UTF-8, кодирует руну, которая
вне диапазона или не является самой короткой кодировкой UTF-8 для
значение. Никакая другая проверка не выполняется.

▾ Пример

основной пакет

Импортировать (
«fmt»
«Юникод / ​​UTF8»
)

func main () {
b: = [] байт («Привет,»)

for len (b)> 0 {
r, размер: = utf8.DecodeRune (b)
fmt.Printf («% c% v \ n», r, размер)

b = b [размер:]
}
}

 H 1
e 1
l 1
l 1
o 1
, 1
  1
世 3
界 3
 

Запустить
Формат

доля

 func DecodeRuneInString (s строка) (r руна, размер int) 

DecodeRuneInString похож на DecodeRune, но его ввод — это строка. Если s
пусто, он возвращает (RuneError, 0). В противном случае, если кодировка недействительна, она
возвращает (RuneError, 1).Оба результата невозможны для правильного, непустого
UTF-8.

Кодировка недействительна, если это неверный UTF-8, кодирует руну, которая
вне диапазона или не является самой короткой кодировкой UTF-8 для
значение. Никакая другая проверка не выполняется.

▾ Пример

основной пакет

Импортировать (
«fmt»
«Юникод / ​​UTF8»
)

func main () {
str: = «Привет, 世界»

for len (str)> 0 {
r, размер: = utf8.DecodeRuneInString (str)
fmt.Printf («% c% v \ n», r, размер)

str = str [размер:]
}
}

 H 1
e 1
l 1
l 1
o 1
, 1
  1
世 3
界 3
 

Запустить
Формат

доля

 func EncodeRune (p [] byte, r rune) int 

EncodeRune записывает в p (который должен быть достаточно большим) кодировку UTF-8 руны.Если руна выходит за пределы допустимого диапазона, она записывает кодировку RuneError.
Возвращает количество записанных байтов.

▾ Пример

основной пакет

Импортировать (
«fmt»
«Юникод / ​​UTF8»
)

func main () {
г: = ‘世’
buf: = make ([] байт, 3)

n: = utf8.EncodeRune (buf, r)

fmt.Println (buf)
fmt.Println (n)
}

Запустить
Формат

доля

▾ Пример (OutOfRange)

основной пакет

Импортировать (
«fmt»
«Юникод / ​​UTF8»
)

func main () {
руны: = [] руна {
// Меньше 0, вне допустимого диапазона.-1,
// Больше 0x10FFFF, вне допустимого диапазона.
0x110000,
// Символ замены Unicode.
utf8.RuneError,
}
for i, c: = range runes {
buf: = make ([] байт, 3)
size: = utf8.EncodeRune (buf, c)
fmt.Printf («% d:% d% [2] s% d \ n», i, buf, size)
}
}

 0: [239 191 189] � 3
1: [239 191 189] � 3
2: [239 191 189] � 3
 

Запустить
Формат

доля

 func FullRune (p [] byte) bool 

FullRune сообщает, начинаются ли байты в p с полной кодировки руны UTF-8.Неверная кодировка считается полной руной, поскольку она преобразуется в руну ошибки шириной 1.

▾ Пример

основной пакет

Импортировать (
«fmt»
«Юникод / ​​UTF8»
)

func main () {
buf: = [] байт {228, 184, 150} // 世
fmt.Println (utf8.FullRune (buf))
fmt.Println (utf8.FullRune (buf [: 2]))
}

Запустить
Формат

доля

 func FullRuneInString (s строка) bool 

FullRuneInString похож на FullRune, но его ввод — это строка.

▾ Пример

основной пакет

Импортировать (
«fmt»
«Юникод / ​​UTF8»
)

func main () {
str: = «世»
fmt.Println (utf8.FullRuneInString (str))
fmt.Println (utf8.FullRuneInString (str [: 2]))
}

Запустить
Формат

доля

 func RuneCount (p [] byte) int 

RuneCount возвращает количество рун в p.Ошибочные и короткие
кодировки рассматриваются как отдельные руны шириной 1 байт.

▾ Пример

основной пакет

Импортировать (
«fmt»
«Юникод / ​​UTF8»
)

func main () {
buf: = [] byte («Привет,»)
fmt.Println («bytes =», len (buf))
fmt.Println («runes =», utf8.RuneCount (buf))
}

Запустить
Формат

доля

 func RuneCountInString (s строка) (n int) 

RuneCountInString похож на RuneCount, но его ввод — это строка.

▾ Пример

основной пакет

Импортировать (
«fmt»
«Юникод / ​​UTF8»
)

func main () {
str: = «Привет, 世界»
fmt.Println («bytes =», len (str))
fmt.Println («runes =», utf8.RuneCountInString (str))
}

Запустить
Формат

доля

 func RuneLen (r rune) int 

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

▾ Пример

основной пакет

Импортировать (
«fmt»
«Юникод / ​​UTF8»
)

func main () {
fmt.Println (utf8.RuneLen (‘a’))
fmt.Println (utf8.RuneLen (‘界’))
}

Запустить
Формат

доля

 func RuneStart (b byte) bool 

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

▾ Пример

основной пакет

Импортировать (
«fmt»
«Юникод / ​​UTF8»
)

func main () {
buf: = [] байт («а 界»)
fmt.Println (utf8.RuneStart (buf [0]))
fmt.Println (utf8.RuneStart (buf [1]))
fmt.Println (utf8.RuneStart (buf [2]))
}

Запустить
Формат

доля

 func Допустимый (p [] байт) bool 

Valid сообщает, состоит ли p полностью из валидных рун в кодировке UTF-8.

▾ Пример

основной пакет

Импортировать (
«fmt»
«Юникод / ​​UTF8»
)

func main () {
действительный: = [] байт («Привет,»)
неверно: = [] байт {0xff, 0xfe, 0xfd}

fmt.Println (utf8.Valid (действительный))
fmt.Println (utf8.Valid (недействительно))
}

Запустить
Формат

доля

 func ValidRune (r rune) bool 

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

▾ Пример

основной пакет

Импортировать (
«fmt»
«Юникод / ​​UTF8»
)

func main () {
действительный: = ‘a’
неверно: = руна (0xfffffff)

fmt.Println (utf8.ValidRune (действительный))
fmt.Println (utf8.ValidRune (недействительно))
}

Запустить
Формат

доля

 func ValidString (s строка) bool 

ValidString сообщает, состоит ли s полностью из допустимых рун в кодировке UTF-8.

▾ Пример

основной пакет

Импортировать (
«fmt»
«Юникод / ​​UTF8»
)

func main () {
действительно: = «Привет, 世界»
неверно: = строка ([] байт {0xff, 0xfe, 0xfd})

fmt.Println (utf8.ValidString (действительный))
fmt.Println (utf8.ValidString (недопустимый))
}

Запустить
Формат

доля

Выбор и применение кодировки символов

Выбор и применение кодировки символов

Целевая аудитория:
HTML-кодеры (с использованием редакторов или сценариев), разработчики сценариев (PHP, JSP и т. Д.)), Кодировщиков CSS, менеджеров веб-проектов и всех, кто плохо знаком с кодировками символов и нуждается в введении в то, как выбирать и применять кодировки символов.

Какую кодировку символов я должен использовать для своего контента и как применить ее к моему контенту?

Контент состоит из последовательности символов. Символы представляют буквы алфавита, знаки препинания и т. Д. Но содержимое хранится в компьютере как последовательность байтов, которые являются числовыми значениями. Иногда для представления одного символа используется более одного байта.Как и коды, используемые в шпионаже, способ преобразования последовательности байтов в символы зависит от того, какой ключ использовался для кодирования текста. В этом контексте этот ключ называется кодировкой символов .

Эта статья предлагает простые советы о том, какую кодировку символов использовать для вашего контента и как ее применять, т. Е. как на самом деле создать документ в этой кодировке.

Если вам нужно лучше понять, что такое символы и кодировки символов, см. Статью Кодировки символов для начинающих .

Выберите UTF-8 для всего содержимого и подумайте о преобразовании любого содержимого из устаревших кодировок в UTF-8.

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

Проверьте, повлияют ли на ваш выбор настройки HTTP-сервера.

Помимо объявления кодировки документа внутри документа и / или на сервере, вам необходимо сохранить текст в этой кодировке, чтобы применить его к вашему контенту.

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

Применение кодировки к вашему контенту

Авторы контента должны объявить кодировку символов своих страниц, используя один из методов, описанных в Объявление кодировок символов в HTML .

Однако важно понимать, что простое объявление кодировки внутри документа или на сервере фактически не изменит байты; вам нужно сохранить текст в этой кодировке , чтобы применить его к вашему контенту.(Объявление просто помогает браузеру интерпретировать последовательности байтов, в которых хранится текст.)

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

Если можете, установите UTF-8 по умолчанию для новых документов в редакторе. На рисунке ниже показано, как это сделать в настройках редактора, такого как Dreamweaver.

Для получения информации о «Форме нормализации Unicode» см. Нормализация в HTML и CSS . Для получения информации о «Подпись Unicode (BOM)» см. Метка порядка байтов (BOM) в HTML .

Вам также может потребоваться проверить, что ваш сервер обслуживает документы с правильными декларациями HTTP, поскольку в противном случае он переопределит информацию в документе (см. Ниже).

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

Зачем использовать UTF-8?

HTML-страница может быть только в одной кодировке. Вы не можете кодировать разные части документа в разных кодировках.

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

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

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

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

Существует три различных кодировки символов Unicode: UTF-8, UTF-16 и UTF-32.Из этих трех только UTF-8 следует использовать для веб-содержимого. Спецификация HTML5 гласит: «Авторам рекомендуется использовать UTF-8. Средства проверки соответствия могут посоветовать авторам не использовать устаревшие кодировки. Инструменты разработки должны по умолчанию использовать UTF-8 для вновь создаваемых документов».

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

Принимая во внимание HTTP-заголовок

Любое объявление кодировки символов в заголовке HTTP переопределит объявления внутри страницы.Если заголовок HTTP объявляет кодировку, отличную от той, которую вы хотите использовать для своего контента, это вызовет проблему, если вы не сможете изменить настройки сервера.

У вас может не быть контроля над объявлениями, которые идут с заголовком HTTP, и вам, возможно, придется обратиться за помощью к людям, которые управляют сервером. С другой стороны, иногда есть способы исправить что-то на сервере, если у вас ограниченный доступ к файлам настройки сервера или если вы создаете страницы с помощью языков сценариев.Например, см. Установка параметра кодировки HTTP для получения дополнительной информации о том, как изменить информацию о кодировке либо локально для набора файлов на сервере, либо для контента, созданного с использованием языка сценариев.

Обычно перед этим необходимо проверить, действительно ли заголовок HTTP объявляет кодировку символов. Вы можете использовать средство проверки интернационализации W3C, чтобы узнать, какая кодировка символов, если таковая имеется, указана в заголовке HTTP. В качестве альтернативы, статья Проверка заголовков HTTP указывает на некоторые другие инструменты для проверки информации о кодировке, передаваемой сервером.

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

Что делать, если я не могу использовать UTF-8?

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

До недавнего времени реестр IANA был местом, где можно было найти имена для кодировок.Реестр IANA обычно включает несколько имен для одной и той же кодировки. В этом случае вы должны использовать имя, обозначенное как
«предпочтительный».

Новая спецификация Encoding теперь предоставляет список, который был протестирован на реальных реализациях браузеров. Вы можете найти список в таблице в разделе «Кодировки». Лучше всего использовать имена из левого столбца этой таблицы.

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

Избегайте этих кодировок

Спецификация HTML5 называет ряд кодировок, которых следует избегать.

Документы не должны использовать JIS_C6226-1983 , JIS_X0212-1990 , HZ-GB-2312 , JOHAB (кодовая страница Windows 1361), кодировки на основе ISO-2022 или кодировки на основе EBIC . Это связано с тем, что они позволяют кодовым точкам ASCII представлять символы, отличные от ASCII, что представляет собой угрозу безопасности.

Документы также не должны использовать кодировки CESU-8 , UTF-7 , BOCU-1 или SCSU , поскольку они никогда не предназначались для веб-содержимого, а спецификация HTML5 запрещает браузерам их распознавать.

Спецификация также настоятельно не рекомендует использовать UTF-16 , а использование UTF-32 «особенно не рекомендуется».

Также следует избегать других кодировок символов, перечисленных в спецификации Encoding .К ним относятся кодировки Big5 и EUC-JP , у которых есть проблемы с совместимостью. ISO-8859-8 (кодировка на иврите для визуально упорядоченного текста) также следует избегать в пользу кодировки, которая работает с логически упорядоченным текстом (например, UTF-8 или в противном случае ISO-8859-8-i).

Кодировка , заменяющая кодировку , указанная в спецификации Encoding , на самом деле не является кодировкой; это резервный вариант, который отображает каждый октет в кодовую точку Unicode U + FFFD REPLACEMENT CHARACTER.Очевидно, что передавать данные в такой кодировке бесполезно.

Определяемая пользователем кодировка x — это однобайтовая кодировка, нижняя половина которой — ASCII, а верхняя половина отображается в область частного использования Unicode (PUA). Как и PUA в целом, лучше избегать использования этой кодировки в общедоступном Интернете, поскольку она наносит ущерб совместимости и долгосрочному использованию.

Кодировок символов для начинающих

Во-первых, какое мне дело?

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

Например, вы можете сделать так, чтобы текст выглядел так:

, но на самом деле он может отображаться так:

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

Так что за кодировка символов?

Слова и предложения в тексте состоят из символов .Примеры символов включают латинскую букву á, китайскую идеограмму 請 или символ деванагари ह.

Возможно, вы не сможете увидеть некоторые символы на этой странице, потому что у вас нет необходимых шрифтов. Если вы нажмете на то место, где вы ожидали увидеть персонажа, вы перейдете к графической версии. Эта страница закодирована в UTF-8.

Персонажи, необходимые для определенной цели, сгруппированы в набор символов (также называемый репертуаром ).(Чтобы однозначно обозначать символы, каждый символ связан с числом, называемым кодовой точкой .)

Символы хранятся в компьютере как один или несколько байтов .

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

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

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

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

Однако в большинстве случаев вам не нужно знать подробности. Вам просто нужно быть уверенным, что вы прислушиваетесь к советам в
раздел Как это влияет на меня? ниже.

Как в это вписываются шрифты?

Шрифт — это набор определений глифов, т.е.определения форм, используемых для отображения символов.

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

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

Как это повлияет на меня?

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

Авторы контента должны узнать, как объявить персонажа
кодировка, используемая для формата документа, с которым они работают.

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

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

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

По ссылкам ниже можно найти дополнительную информацию по этим темам.

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

Обратите внимание, что номера кодовых точек обычно выражаются в шестнадцатеричной системе счисления, т.е. основание 16. Например, 233 в шестнадцатеричной форме — это E9.Значения кодовой точки Unicode обычно записываются в форме U + 00E9.

В наборе кодированных символов под названием ISO 8859-1 (также известном как Latin1) значение десятичной кодовой точки для буквы é равно 233. Однако в ISO 8859-5, та же кодовая точка представляет кириллический символ щ.

Эти наборы символов содержат менее 256 символов и напрямую сопоставляют кодовые точки с байтовыми значениями, поэтому кодовая точка со значением 233 представлена ​​одним байтом со значением 233.Обратите внимание, что только контекст определяет, представляет ли этот байт либо é, либо щ.

Есть и другие способы обработки символов из ряда сценариев. Например, с набором символов Unicode вы можете представить оба символа в одном наборе. Фактически, Юникод
содержит в одном наборе, вероятно, все символы, которые вам когда-либо понадобятся. Хотя буква é по-прежнему представлена ​​значением кодовой точки 233,
кириллический символ щ теперь имеет значение кодовой точки 1097.

С другой стороны, 1097 слишком большое число, чтобы его можно было представить одним
байт*. Итак, если вы используете кодировку символов для текста Unicode под названием UTF-8, щ будет представлен двумя байтами. Тем не менее
значение кодовой точки не просто выводится из значения двух байтов, соединенных вместе — требуется более сложное декодирование.

Другой Unicode
символы отображаются в один, три или четыре байта в кодировке UTF-8.

Кроме того, обратите внимание, что буква é также представлена ​​двумя байтами в UTF-8, а не одним байтом, используемым в ISO 8859-1. (Только символы ASCII кодируются одним байтом в UTF-8.)

UTF-8 — это наиболее широко используемый способ представления текста Unicode на веб-страницах, и вы всегда должны использовать UTF-8 при создании веб-страниц и баз данных. Но, в принципе, UTF-8 — лишь один из возможных способов кодирования.
Символы Юникода. Другими словами, одна кодовая точка в наборе символов Unicode может фактически отображаться в разные последовательности байтов, в зависимости от
какая кодировка использовалась для документа.Кодовые точки Unicode могут быть сопоставлены с байтами с использованием любой из кодировок, называемых UTF-8, UTF-16 или UTF-32.
Символ деванагари क с кодовой точкой 2325 (что составляет 915 в шестнадцатеричной системе счисления) будет представлен двумя
байтов при использовании кодировки UTF-16 (09 15), трех байтов с UTF-8 (E0 A4 95) или четырех байтов с UTF-32 (00 00 09 15).

Могут быть и другие сложности помимо описанных в этом разделе (например, порядок байтов и escape-последовательности), но детали
описанное здесь показывает, почему важно, чтобы приложение, с которым вы работаете, знало, какая кодировка символов подходит для ваших данных, и
знает, как обрабатывать эту кодировку.

Как работает кодировка Unicode UTF-8

UTF-8 — это умный способ кодирования текста Unicode. Я упоминал об этом пару раз в последнее время, но я не писал о UTF-8 как таковой. Поехали.

Решает проблему UTF-8

Клавиатуры

для США часто могут отображать 101 символ, что предполагает, что 101 символа будет достаточно для большинства английского текста. Семи битов будет достаточно для кодирования этих символов, поскольку 2 7 = 128, и именно это делает ASCII . Он представляет каждый символ с 8 битами, поскольку компьютеры работают с битами в группах размеров, которые являются степенями двойки, но первый бит всегда равен 0, потому что он не нужен. Extended ASCII использует оставшееся пространство в ASCII для кодирования большего количества символов.

Некоторым пользователям может пригодиться 256 символов, но это не позволит вам представлять, например, китайский язык. Первоначально Unicode хотел использовать два байта вместо одного для представления символов, что позволило бы использовать 2 16 = 65 536 возможностей, что достаточно для захвата многих мировых систем письма. Но не все, и поэтому Unicode расширился до четырех байтов.

Если бы вы сохраняли английский текст, используя два байта для каждой буквы, половина места была бы потрачена на хранение нулей.А если вы используете четыре байта на букву, три четверти пространства будут потрачены впустую. Без какой-либо кодировки каждый файл, содержащий тест по английскому, был бы в два или четыре раза больше необходимого . И не только на английском, но и на всех языках, которые могут быть представлены с помощью ASCII.

UTF-8 — это способ кодирования Unicode, чтобы текстовый файл ASCII кодировал сам себя. Нет лишнего места, кроме начального бита каждого байта, который ASCII не использует. И если ваш файл в основном представляет собой текст ASCII с добавлением нескольких символов, отличных от ASCII, символы, отличные от ASCII, просто сделают ваш файл немного длиннее.Вам не нужно внезапно заставлять каждый символ занимать в два или четыре раза больше места только потому, что вы хотите использовать, скажем, знак евро € (U + 20AC).

Как это делает UTF-8

Поскольку первый бит символов ASCII установлен в ноль, байты с первым битом, установленным в 1, не используются и могут использоваться специально.

Когда программа, читающая UTF-8, встречает байт, начинающийся с 1, она подсчитывает, сколько единиц следует до появления 0. Например, в байте формы 110xxxxx после начальной 1 стоит одна 1.Пусть n будет числом единиц между начальной 1 и первым 0. Оставшиеся биты в этом байте и некоторые биты в следующем n байтах будут представлять символ Unicode. Число n не обязательно должно быть больше 3 по причинам, о которых мы поговорим позже. То есть для представления символа Юникода с использованием UTF-8 требуется не более четырех байтов.

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

Байт формы 1110xxxx содержит четыре бита символа Юникода и говорит, что остальные биты приходятся на следующие два байта.

Байт формы 11110xxx содержит три бита символа Юникода и говорит о том, что остальные биты приходятся на следующие три байта.

После начального байта, объявляющего начало символа, распределенного по нескольким байтам, биты сохраняются в байтах в форме 10xxxxxx. Поскольку начальные байты многобайтовой последовательности начинаются с двух битов 1, двусмысленности нет: байт, начинающийся с 10, не может обозначать начало новой многобайтовой последовательности.То есть UTF-8 является самопунктурирующим.

Итак, многобайтовые последовательности имеют одну из следующих форм.

 110xxxxx 10xxxxxx
    1110xxxx 10xxxxxx 10xxxxxx
    11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
 

Если посчитать крестики в нижнем ряду, их 21. Таким образом, эта схема может представлять только числа длиной до 21 бита. Разве нам не нужны 32 бита? Оказывается, нет.

Хотя символ Unicode якобы является 32-битным числом, на самом деле для кодирования символа Unicode требуется не более 21 бита по причинам, описанным здесь.Вот почему n , количество единиц, следующих за начальной 1 в начале многобайтовой последовательности, должно быть только 1, 2 или 3. Схема кодирования UTF-8 может быть расширена, чтобы разрешить n = 4 , 5 или 6, но в этом нет необходимости.

КПД

UTF-8 позволяет вам взять обычный файл ASCII и рассматривать его как файл Unicode, закодированный с помощью UTF-8. Таким образом, UTF-8 так же эффективен, как ASCII, с точки зрения пространства. Но не по времени. Если программное обеспечение знает, что файл на самом деле является ASCII, оно может принимать каждый байт по номиналу, не проверяя, является ли он первым байтом многобайтовой последовательности.

И хотя простой ASCII является допустимым для UTF-8, расширенный ASCII — нет. Таким образом, расширенные символы ASCII теперь занимали два байта вместо одного. Мое предыдущее сообщение было о путанице, которая могла возникнуть из-за того, что программное обеспечение интерпретировало файл в кодировке UTF-8 как расширенный файл ASCII.

Похожие сообщения

UTF-8 Кодировка


Сводка

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

UTF означает формат преобразования Unicode. ‘8’ означает, что он использует 8-битные блоки для
представляют собой персонажа. Количество блоков, необходимых для представления персонажа, варьируется от
От 1 до 4.

Одной из действительно хороших особенностей UTF-8 является то, что он совместим со строками с завершающим нулем.
При кодировании ни один символ не будет иметь нулевой (0) байт. Это означает, что код C, имеющий дело с
char [] будет «просто работать».

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

Если вы разработчик приложений, эта статья Joel On Software о Unicode
— довольно хорошее резюме всего, что вам нужно знать.

Дополнительные ссылки:


Деталь

Для любого символа, равного или меньше 127 (шестнадцатеричный 0x7F), представление UTF-8
это один байт. Это всего лишь младшие 7 бит полного значения Unicode.
Это также то же самое, что и значение ASCII.

Для символов, равных или меньше 2047 (шестнадцатеричное 0x07FF), представление UTF-8
распространяется на два байта.В первом байте будут установлены два старших бита и
третий бит очищен (т.е. от 0xC2 до 0xDF). Второй байт будет иметь
установлен верхний бит, а второй бит очищен (то есть от 0x80 до 0xBF).

Для всех символов, равных или больше 2048, но меньше 65535 (0xFFFF), представление UTF-8
распространяется на три байта.

В следующей таблице показан формат таких байтовых последовательностей UTF-8 (где
«свободные биты», обозначенные в таблице значками x, объединяются в
порядок показан и интерпретируется от наиболее значимого до наименее значимого).

Двоичный формат байтов в последовательности

1-й байт 2-й байт 3-й байт 4-й байт Количество свободных битов Максимальное выражаемое значение Unicode
0xxxxxxx 7 007F шестигранник (127)
110xxxxx 10xxxxxx (5 + 6) = 11 07FF шестигранник (2047)
1110xxxx 10xxxxxx 10xxxxxx (4 + 6 + 6) = 16 FFFF шестигранник (65535)
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx (3 + 6 + 6 + 6) = 21 10FFFF шестигранник (1,114,111)

Значение каждого отдельного байта указывает его функцию UTF-8, как показано ниже:

  • От 00 до 7F шестнадцатеричное (от 0 до 127): первый и единственный байт последовательности.
  • от 80 до BF шестнадцатеричный (от 128 до 191): продолжающий байт в многобайтовой последовательности.
  • C2 в шестнадцатеричный формат DF (194–223): первый байт двухбайтовой последовательности.
  • E0 в шестнадцатеричном формате EF (от 224 до 239): первый байт трехбайтовой последовательности.
  • F0 — FF шестнадцатеричный (от 240 до 255): первый байт четырехбайтовой последовательности.

UTF-8 остается простым однобайтовым, совместимым с ASCII методом кодирования до тех пор, пока
непосредственно присутствуют символы больше 127. Это означает, что документ HTML технически
объявленный как закодированный как UTF-8, может оставаться обычным однобайтовым файлом ASCII.Документ может остаться
поэтому, даже если он может содержать символы Unicode выше 127, при условии, что все символы выше 127 упоминаются
косвенно с помощью амперсандных сущностей.

Примеры закодированных символов Unicode (в шестнадцатеричной системе счисления)

16-битный Unicode Последовательность UTF-8
0001 01
007F 7F
0080 C2 80
07FF DF BF
0800 E0 A0 80
FFFF EF BF BF
010000 F0 90 80 80
10FFFF F4 8F BF BF

.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *