Веб и кодирование

ASCII и UTF-8: в чём разница и где здесь Unicode

Для байтов 00–7F ASCII и UTF-8 дают одинаковый текст. Разница появляется, когда в строке встречаются кириллица, буквы с диакритикой, деванагари или эмодзи.

Опубликовано

ASCII, Unicode и UTF-8 описывают разные вещи

ASCII — семибитный набор кодов, который обычно хранят в байтах с нулевым старшим битом. UTF-8 сохраняет эти значения. Unicode не равен UTF-8: ту же кодовую точку можно записать в UTF-16 или UTF-32.

НазваниеЧто описываетПример
ASCII128 кодов, включая управляющие символыA = 65 в десятичной системе = 41 в hex
UnicodeКодовые точки для разных письменностейक = U+0915
UTF-8Запись скалярных значений Unicode в байтахक = E0 A4 95

Одни и те же байты ASCII подходят для UTF-8

Каждый байт примера меньше 80 в hex. В ASCII и UTF-8 последовательность читается как Hello. Совместимость распространяется и на управляющие коды, например перевод строки 0A; это не делает все байты печатными.

48 65 6C 6C 6F
Hello
ТекстКодовая точкаБайты UTF-8Есть в ASCII?
AU+004141Да
éU+00E9C3 A9Нет
ЯU+042FD0 AFНет
कU+0915E0 A4 95Нет
😀U+1F600F0 9F 98 80Нет

Кириллица и деванагари занимают несколько байтов

Здесь буква Я занимает два байта, пробел — один, а क — три. Если читать каждый байт как самостоятельный символ, структура UTF-8 теряется. Переключите пример ниже между ASCII и UTF-8 и сравните результат.

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

D0 AF 20 E0 A4 95
Я क

Байты вне ASCII не обязательно являются UTF-8

После C3 нужен байт продолжения в диапазоне 80–BF. Следующий байт 28 — открывающая скобка, которая не может продолжить эту последовательность. Режим UTF-8 сообщает об ошибке; символ замены обозначает потерю декодирования, а не восстановленный исходный текст.

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

C3 28

Явно задавайте кодировку в Python

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

text = "Я क"
raw = text.encode("utf-8")
print(raw.hex(" "))  # d0 af 20 e0 a4 95
print(bytes.fromhex("d0 af 20 e0 a4 95").decode("utf-8"))
# bytes.fromhex("c3 28").decode("utf-8") raises UnicodeDecodeError

Расширенный ASCII и UTF-16 — отдельные случаи

«Расширенный ASCII» — неофициальное название нескольких несовместимых восьмибитных кодировок. Единой таблицы для диапазона 80–FF нет. Совместимость UTF-8 относится к стандартному ASCII.

UTF-16 тоже представляет Unicode, но записывает другие байты: A — это 41 00 в UTF-16LE или 00 41 в UTF-16BE. BOM, метаданные файла и описание протокола помогают определить кодировку; успешного декодирования самого по себе недостаточно.

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

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

Частые вопросы

Любой ASCII-файл является корректным UTF-8?

Последовательность стандартных ASCII-байтов 00–7F корректна в UTF-8 и обозначает те же символы. Это не гарантирует правильность синтаксиса самого формата файла.

Можно ли записать русский текст или хинди в ASCII?

Стандартный ASCII не содержит кириллицу и деванагари. Используйте Unicode-кодировку, например UTF-8. Шрифт, рисующий другой знак поверх ASCII-кода, не меняет сохранённый символ.

UTF-8 всегда занимает больше места, чем ASCII?

Для текста только из ASCII число байтов одинаковое. Остальные символы занимают несколько UTF-8-байтов; длина в байтах и количество видимых символов — разные величины.

Проверьте пример

Начните с байтов ASCII

Декодируйте Hello и переключитесь между ASCII и UTF-8.

48 65 6C 6C 6F

Ожидаемый результат: Оба режима показывают Hello; во входе пять байтов.

Проверьте пример

Декодируйте кириллицу и деванагари

Двухбайтная буква, пробел и трёхбайтная буква образуют одну UTF-8-строку.

D0 AF 20 E0 A4 95

Ожидаемый результат: UTF-8 показывает Я क. Шесть байтов не равны шести самостоятельным символам.

Проверьте пример

Проверьте ошибочную UTF-8-последовательность

Байт 28 не может продолжить последовательность, начатую C3.

C3 28

Ожидаемый результат: Режим UTF-8 сообщает об ошибке. Символ замены не восстанавливает исходное значение.

Проверьте байты

Сравните результат ASCII и UTF-8

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

Открыть Hex to ASCII Converter →

Документация и стандарты