Кодирование информации — это преобразование данных из одной формы представления в другую по известным правилам (коду), чтобы их было удобно хранить, передавать и обрабатывать. Ключевое слово тут — «известные правила»: кодирование не прячет данные и не требует секрета, обратное преобразование делает любой, кто знает тот же код.
Содержание
Дальше разберем, как компьютер сводит любые данные к нулям и единицам, что такое кодировки текста ASCII, Unicode и UTF-8, проследим сквозную цепочку «символ -> код-поинт -> байты» на одном примере и явно разведем три понятия, которые постоянно путают: кодирование, шифрование и сжатие.
Мини-словарь: три пары, которые путают
Чтобы примеры дальше не казались противоречивыми, разведем термины сразу.
- Кодирование — смена формы записи по открытым правилам (текст -> байты, число -> двоичный код). Обратимо без секрета.
- Шифрование — смена формы записи так, чтобы прочитать мог только владелец ключа. Обратимо только с ключом.
- Сжатие — уменьшение объема данных. Обратимо без секрета (если сжатие без потерь).
И отдельно — три уровня внутри текста, их тоже смешивают:
- Набор символов (character set) — справочник, который каждому символу дает номер.
- Кодовая точка (code point) — этот номер, например
U+042Fдля буквы «Я». - Кодировка (encoding) — правило, по которому кодовая точка превращается в конкретные байты (UTF-8, UTF-16, cp1251).
Двоичное представление: биты и байты
Компьютер хранит и обрабатывает данные в двоичном виде — последовательностью двух состояний, которые записывают как 0 и 1. Один такой разряд называется битом. Физически это упрощение: за нулем и единицей стоят разные уровни сигнала или заряда, а не буквальное «есть ток / нет тока» — реализация зависит от типа памяти.
Сколько вариантов кодирует группа бит, считается по формуле 2 в степени числа бит:
- 1 бит — 2 варианта (
0,1); - 2 бита — 4 варианта (
00,01,10,11); - 8 бит — 256 вариантов.
Восемь бит — это байт, базовая единица адресации в большинстве систем. В один байт помещается число от 0 до 255. Любые данные — числа, текст, изображение, звук — в итоге превращаются в поток байт; различаются только правила, по которым это делается. Дальше в качестве сквозного примера берем текст, потому что на нем виднее разница между уровнями.
Кодировки текста: ASCII, Unicode, UTF-8
Чтобы записать текст байтами, нужна договоренность «какому символу какой номер и какие байты соответствуют». Исторически таких договоренностей было несколько.
ASCII — таблица на 7 бит, то есть 128 кодовых точек (номера 0-127). Их хватает на латиницу, цифры, знаки препинания и управляющие символы. Кириллицы, умляутов и прочего в ASCII нет.
Восьмибитные (однобайтовые) кодировки расширили ASCII до 256 символов: первые 128 совпадают с ASCII, а вторая половина отдана под национальные алфавиты. Отсюда «зоопарк» несовместимых таблиц — cp1251 и KOI-8 для кириллицы, ISO 8859-1 для западноевропейских языков и так далее. Один и тот же байт в разных таблицах означает разные буквы, поэтому текст, прочитанный «не той» кодировкой, превращается в мусор.
Unicode решает эту путаницу иначе. Это не «двухбайтовая кодировка», как часто пишут, а единый набор символов: он присваивает кодовую точку каждому символу всех письменностей. Диапазон кодовых точек — от U+0000 до U+10FFFF, реально назначено более 150 тысяч символов (Unicode 16.0, 2024). Сам по себе Unicode говорит только «какой символ под каким номером», но не «сколько это байт».
Байты задает уже кодировка Unicode — UTF-8, UTF-16 или UTF-32. Сегодня стандарт для веба и большинства файлов — UTF-8: она переменной длины, кодирует символ в 1-4 байта и обратно совместима с ASCII (первые 128 символов занимают ровно 1 байт, как в ASCII). Детальный разбор устройства UTF-8 и других форматов — в отдельной статье (ссылка в конце); здесь важно понять роль каждого уровня.
Сквозная цепочка: символ -> код-поинт -> байты
Соберем три уровня в одну линию на слове Яndex. В Python номер символа дает ord, а байты в UTF-8 — метод encode:
text = "Яndex"
for ch in text:
cp = ord(ch) # кодовая точка
b = ch.encode("utf-8") # байты в UTF-8
print(f"{ch!r:>6} -> U+{cp:04X} -> {b.hex(' ').upper()}")
data = text.encode("utf-8")
print("bytes:", data.hex(" ").upper())
print("decoded back:", data.decode("utf-8"))
Фактический вывод:
'Я' -> U+042F -> D0 AF
'n' -> U+006E -> 6E
'd' -> U+0064 -> 64
'e' -> U+0065 -> 65
'x' -> U+0078 -> 78
bytes: D0 AF 6E 64 65 78
decoded back: Яndex
Видно все три уровня: символ «Я», его кодовая точка U+042F и два байта D0 AF в UTF-8. Латинские буквы занимают по одному байту, совпадающему с их ASCII-кодом (n — это 6E). Поэтому строка из 5 символов заняла 6 байт: длина в символах и длина в байтах — разные величины.
Если те же байты прочитать другой кодировкой, получится мусор (mojibake) — потому что байты одни, а таблицы разные:
b = "Яndex".encode("utf-8") # D0 AF 6E 64 65 78
print(b.decode("cp1251")) # РЇndex
try:
b.decode("ascii")
except UnicodeDecodeError as e:
print("ascii error:", e)
Фактический вывод:
РЇndex
ascii error: 'ascii' codec can't decode byte 0xd0 in position 0: ordinal not in range(128)
Отсюда практическое правило: байты бессмысленны без указания кодировки, которой их читать. cp1251 «успешно» прочитала UTF-8-байты, но выдала неверный текст; ASCII честно упала, потому что байта 0xD0 в ней нет.
Оговорка про уровни: кодовая точка — это не всегда один видимый символ (графема). Некоторые эмодзи и буквы с диакритикой складываются из нескольких кодовых точек, поэтому len(строки) может не совпадать с числом символов, которые видит человек. Для базового текста эта разница не важна, но помнить о ней стоит.
Кодирование, шифрование и сжатие — в чем разница
Все три операции меняют форму данных, но с разной целью и с разной обратимостью. Различать их удобно по одному вопросу: нужен ли секрет, чтобы вернуть исходные данные.
| Свойство | Кодирование | Шифрование | Сжатие |
|---|---|---|---|
| Цель | сменить форму записи | скрыть содержимое | уменьшить объем |
| Нужен секрет для обратного хода | нет | да, ключ | нет |
| Кто может расшифровать | любой, кто знает код | только владелец ключа | любой (для сжатия без потерь) |
| Меняет ли объем | обычно нет специально | обычно нет специально | да, это и есть цель |
| Пример | UTF-8, base64 | AES, RSA | ZIP, gzip |
Небольшой прогон подтверждает грань «секрет не нужен» для кодирования и сжатия:
import base64, zlib
raw = "Привет, мир!".encode("utf-8")
enc = base64.b64encode(raw) # кодирование, обратимо без секрета
print("base64:", enc.decode())
print("обратно:", base64.b64decode(enc).decode("utf-8"))
long = ("данные " * 20).encode("utf-8")
comp = zlib.compress(long) # сжатие без потерь
print("сжатие:", len(long), "->", len(comp), "байт")
print("обратимо:", zlib.decompress(comp) == long)
Фактический вывод:
base64: 0J/RgNC40LLQtdGCLCDQvNC40YAh
обратно: Привет, мир!
сжатие: 260 -> 26 байт
обратимо: True
base64 — это именно кодирование: она превращает байты в набор безопасных ASCII-символов и разворачивается обратно без всякого ключа (это не защита данных). zlib сжала повторяющийся текст в 10 раз и вернула его без потерь. Ни в том, ни в другом случае секрет не нужен — в отличие от шифрования, где без ключа исходные данные не восстановить.
Выводы
- Кодирование — это смена формы записи по открытым правилам; секрет для обратного преобразования не нужен, этим оно отличается от шифрования.
- В основе всего лежит двоичное представление: бит — это
0/1, байт — 8 бит и 256 значений; любые данные в итоге становятся байтами. - В тексте различают три уровня: набор символов (кто под каким номером), кодовая точка (сам номер,
U+042F) и кодировка (какими байтами номер записать). - Unicode — это набор символов, а не кодировка; конкретные байты задают UTF-8/UTF-16/UTF-32, сегодня по умолчанию — UTF-8 (1-4 байта, совместима с ASCII).
- Байты нельзя правильно прочитать, не зная их кодировки: те же байты в другой таблице дают мусор (mojibake).
Где применяется / связь с практикой
Понимание уровней «символ -> код-поинт -> байты» экономит часы отладки: кракозябры в консоли, письмах и импортах CSV почти всегда сводятся к чтению байт не той кодировкой, а не к «испорченному файлу». Тот же навык нужен при работе с файлами, сетевыми протоколами и базами данных, где кодировку задают явно.
Освойте тему на практике
Разложить эти механики по полочкам и закрепить их на практике помогает курс Python Basic: на нем разбирают работу со строками, байтами и файлами на реальных задачах. Посмотреть формат занятий и задать вопросы преподавателю можно на открытых уроках Otus — они бесплатные.
Смежные темы: Кодировки символов и формат UTF-8, Кодирование и декодирование: что должен знать программист.
FAQ
Почему в файле «5 символов», а размер 6 байт?
Потому что в UTF-8 длина в байтах зависит от символов: латиница и цифры занимают 1 байт, кириллица — 2 байта, часть символов — 3-4 байта. Число символов и число байт совпадают только для чистого ASCII.
Можно ли по байтам однозначно понять, какая это кодировка?
Строго — нет. Иногда помогает BOM (метка порядка байт) в начале файла или эвристики, но универсального признака нет; поэтому кодировку принято указывать явно (в заголовке HTTP, атрибуте файла, параметре чтения).
base64 — это шифрование, раз текст стал нечитаемым?
Нет. base64 — кодирование: она разворачивается обратно без ключа, ее делает кто угодно. Для защиты данных нужно шифрование с ключом, а не base64.



