Если вы программист или хотя бы немного связаны с программированием
1, то без сомнения сталкивались с таблицей
ASCII.
Таблица ASCII полезна. Но знали ли вы, что она ещё
красива и изящна?
Сегодня даже не близкие к программированию люди могут знать об ASCII благодаря книгам и фильмам наподобие «Марсианина»2
ASCII по-прежнему с нами; даже если вы передаёте современный Unicode
3, то должны знать, что самый популярный формат кодировки UTF-8 специально спроектирован как обратно совместимый с ASCII! Декодировав эту статью как ASCII, вы в целом поймёте её смысл… если закроете глаза на мусорные символы в конце предложений (прим. ред.: имеет смысл только для оригинальной статьи на английском).
1. Связаны с программированием? Ага. Например, геокэшеры, которые хотя бы раз кодировали геокэш с координатами, заданными в двоичном виде (то есть в двоичном представлении ASCII) в данном случае считаются «связанными с программированием».
2. И в книге, и в фильме Марк Уотни разделяет круг рядом с восстановленной станцией Pathfinder на сегменты, соответствующие шестнадцатеричным цифрам от 0 до F, чтобы поворот камеры (выполняемый операторами с Земли) мог передавать пары 4-битных слов. Два 4-битных слова составляют 8-битный байт, который можно декодировать как ASCII, восстановив таким образом связь с Землёй.
3. Например, чтобы отправлять свои любимые эмодзи.
История
Изначально кодировка ASCII была стандартизирована в документе с легко запоминающимся названием
X3.4-1963, где было присвоено значение сотне из потенциальных 128 кодовых точек, представляемых в двоичном 7-битном виде
4, то есть двоичными значениями от 0000000 до 1111111:
Можно заметить, что в этой первой реализации отсутствует… весь алфавит в нижнем регистре! Есть тут и некоторые странности, на которые могут обратить внимание фанаты современного ASCII, например, любопытные стрелки влево и вправо внизу столбца 101____, а также управляющие коды ACK и ESC в столбце 111____.
4. ASCII многие считают 8-битным кодом, но на самом деле он 7-битный. Поэтому почти в каждом ASCII-сообщении практически все октеты начинаются с нуля. 8 битов удобны для передачи, но первые 8-битные системы чаще всего использовали восьмой бит для проверки чётности, чтобы выявлять ошибки передачи. Разумеется, при этом ничто не мешает передавать один за другим поток 7-битных символов.
Если вы уже догадались, к чему я веду, то вам должно быть интересно взглянуть на таблицу X3.4-1963 и убедиться в том, что многие из тех же изящных решений
уже существовали в 1963 году. Это очень круто!
Таблица
На случай, если вы ещё незнакомы с таблицей, давайте рассмотрим её. Я отметил цветом некоторые её части, которые считаю самими красивыми:
В этой таблице показаны только десятеричные и шестнадцатеричные значения символов, но чтобы оценить её красоту, нам понадобятся и двоичные.
▍ Управляющие коды
Первые 32 «символа» (и, можно сказать, последний тоже) мы не можем
увидеть, это команды, передаваемые между машинами. Возможно, вам известен «возврат каретки» (carriage return,
0D
) и «перевод строки» (line feed,
0A
), означающие «вернуться к началу этой строки» и «перейти на следующую строку»
5.
5. Во времена, когда данные отправлялись телетайпным принтерам, эти два символа имели сильно отличающееся значение; иногда устройства так медленно возвращали головки в левую часть бумаги, что требовалось дополнительно отправлять несколько нулевых байтов, например 0D 0A 00 00 00 00
, чтобы печатающая головка точно оказывалась в нужном месте до отправки новых данных: тогда у принтеров ещё не было буферов памяти! Ради совместимости с телетайпами в первых миникомпьютерах соблюдался тот же стандарт «возврат каретки плюс перевод строки» даже при выводе текста на экраны. В дальнейшем для сохранения обратной совместимости уже с этими системами следующее поколение компьютеров тоже для обозначения следующей строки использовало символ возврата каретки и перевода строки. Поэтому даже сегодня многие компьютерные системы (в том числе по большей мере Windows и многие протоколы Интернета) продолжают использовать комбинацию возврата каретки и символа перевода строки каждый раз, когда им нужно перейти на следующую строку; эта избыточность встроена в цепь обратной совместимости, устаревшей уже десятки лет назад, но оставшейся с нами навечно как часть нашего цифрового наследия.
Многие из прочих больше широко не используются, они были спроектированы для компьютерных систем, совершенно отличающихся от нынешних, но всё равно присутствуют в таблице.
Число 32 является степенью двойки, то есть можно логично предположить, что эти управляющие коды имеют в своём двоичном виде определённый математический «паттерн», отличающий их от остальной части таблицы. И это действительно так! Все управляющие коды соответствуют паттерну
00_____
, то есть начинаются с двух нулей. Поэтому когда мы считываем 7-битный элемент ASCII
6, то если он начинается с
00
, это непечатаемый символ. Все остальные символы печатаемы.
6. Получили 8 двоичных цифр? Вероятно, первая равна нулю. Отбрасываем её. Теперь мы получили 7-битный ASCII. Вот и всё.
Этот паттерн не только упрощает чтение кодировки людьми (таким образом повышая его упорядоченность и усиливая красоту), но и помогает, если вы работаете на древней медленной компьютерной системе, сравнивающей по одному биту информации за раз. В таком случае можно использовать дерево принятия решений для ускорения работы.
Среди управляющих кодов есть одно исключение:
DEL, последний символ таблицы, соответствующий двоичному числу
1111111
. Это привет из прошлого, когда работа велась с бумажными лентами: для обозначения нулей и единиц клавиатура пробивала комбинации из семи отверстий.
Удалять отверстия после их пробивания было нельзя, поэтому единственным способом пометить символ как недействительный была перемотка ленты и пробивание
всех отверстий в этой позиции, то есть всех единиц.
▍ Пробел
Первый печатаемый символ — это пробел; это
невидимый символ, но он всё равно значим для людей, так что это не управляющий символ (сегодня это кажется очевидным, то при изначальном обсуждении стандарта ASCII это вызвало споры о семантике).
Помещение его численно
перед всеми печатаемыми символами было очень продуманным и преднамеренным решением. Причина этого заключается в
сортировке. Проще всего компьютеру отсортировать список (файлов, строк или чего-то ещё)
численным способом, применив ту же таблицу преобразования символов, что и для всего другого
7.
7. Я крайне благодарен разделу 13.8 книги Coded Character Sets, History and Development Чарльза Маккензи (1980 год), весь текст которой выложен бесплатно онлайн, за помощь в понимании важности позиции символа пробела в наборе символов ASCII. Основную часть изложенного в посте я уже знал давно, но раньше я не осознавал полностью важность расположения пробела!
Естественнее всего, чтобы символ пробела шёл перед всеми остальными символами, или же в отсортированном компьютером списке John Smith не будет идти перед Johnny Five, как мы того ожидаем.
Кроме того, что это первый печатаемый символ, пробел имеет красивый и запоминающийся двоичный вид, легко узнаваемый человеком:
0100000
.
▍ Числа
Расположение арабских чисел 0-9 тоже не было совпадением. Их позиция означает, что они начинаются с нуля, находящегося в красивом круглом двоичном значении
0110000
(и аналогично круглом шестнадцатеричном значении
30
) и продолжаются последовательно:
Последние четыре разряда двоичного числа описывают
значение соответствующей десятеричной цифры.
Кроме того, последний разряд шестнадцатеричного числа
равен десятеричной цифре. Это просто потрясающе!
Если вы решили использовать этот пост, чтобы научиться мысленно «читать» ASCII в двоичном виде, то следует запомнить такое правило: если символ начинается с
011
, то оставшуюся часть числа нужно воспринимать как двоичное представление
самого числа. Вероятно, вы не ошибётесь: если получившееся число больше 9, то, скорее всего, это уже какой-то знак препинания.
▍ Числа с шифтом
Вычтите
0010000
из каждого числа, и вы получите
числа с шифтом. К сожалению, первое уже занято символом пробела, но в случае всех остальных символы являются тем,
что вы получаете при одновременном нажатии на клавишу Shift и числовую клавишу.
«Но ведь нет!», — воскликнете вы. Да, возможно, вы правы. Я печатаю на 105-клавишной QWERTY-клавиатуре ISO/UK и только
четыре из девяти цифр 1-9 правильно отражены в таблице ASCII.
Боюсь, это вызвано тем, что ASCII создан на основе не современных компьютерных клавиатур, а позиций механической пишущей машинки Remington No. 2, раскладка со сдвигом которой, вероятно, в те времена была компромиссом, наиболее близким к стандарту. Но если вас это утешит, то можно сказать, что вы узнали что-то новое о пишущих машинках.
Любопытный факт в нагрузку: в первых механических пишущих машинках не было цифры 1: ожидалось, что вместо неё будет использоваться буква I. Для печати это нормально, но не особо удобно для считываемых компьютером данных.
▍ Буквы
Как и цифры, буквы имеют
паттерн. После символа
@
со значением
1000000
все буквы в верхнем регистре начинаются с
10
, а далее идёт
двоичное представление их позиции в алфавите. 1 = A =
1000001
, 2 = B =
1000010
и так далее до 26 = Z =
1011010
. Если вы сможете выучить числа позиций букв алфавита, то умеете считать в двоичном коде, и этого будет достаточно, чтобы прочитать любую букву верхнего регистра в ASCII, закодированную в двоичном виде
8.
8. Я уверен, что вы уже это знаете, но на случай, если вы один из сегодняшних 10000 счастливчиков, скажу, что причина того, что мы называем заглавные и строчные буквы верхним (uppercase) и нижним (lowercase) регистром, связана с печатью в 19-м веке, когда наборный шрифт хранился в коробках (type case) в зависимости от типа символа. Обычно заглавные буквы хранились в верхнем (upper) ящике.
А разобравшись с верхним регистром, легко понять и нижний. Позиция этих символов в таблице означает, что они ровно на
0100000
выше, чем соответствующая буква в верхнем регистре; то есть все буквы в нижнем регистре начинаются с
11
! 1 = a =
1100001
, 2 = b =
1100010
, а 26 = z =
1111010
.
Возможно, вам непонятно, почему буквы в верхнем регистре идут
первыми — причина снова в сортировке; кроме того,
первая реализация ASCII, которую мы видели выше, была придумана ещё до того, как стало понятно, что компьютерным системам
нужно будет разделять коды символов букв в верхнем и нижнем регистре (можно разработать альтернативную реализацию, которая бы вместо этого, например, передавала управляющие коды, сообщающие получателю о необходимости смены регистра). Учитывая современные технологии, я рад, что в конечном итоге разработчики стандарта выбрали правильное решение.
Красота
ASCII обладает странным неуловимым очарованием. Мы используем этот стандарт (и производные от него) буквально
каждый день, поэтому легко подумать, что это просто какая-то произвольная кодировка.
Но решения, принятые при выборе того, какие потоки нулей и единиц будут описывать символы, раскрывают продуманную логику. Она эстетически приятна и усеяна историческими артефактами, позволяющими нам узнать о тайной истории компьютеров. И она построена на основе паттернов, достаточно сложных для упрощения мощных вычислений и в то же время достаточно согласованных для запоминания, изучения и понимания человеком.
Telegram-канал со скидками, розыгрышами призов и новостями IT 💻
![](https://habrastorage.org/webt/tp/sk/z-/tpskz-7w7a8e74isoowuep40xeg.png)