Представление информации: язык программирования Python и кодировки

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

Содержание:

Как было сказано в предыдущих статьях, любое различимое состояние можно использовать для кодирования информации. В электронных приборах таких состояний всего 2: «включено», «выключено». В английском алфавите 26 букв, а это значит, что достаточно 5 бит для представления каждой буквы. Общее количество состояний которые могут быть интерпретированы 2^5=32. Если учитывать большие и малые буквы, тогда для 52 символов требуется 6 бит.

Однако, кроме основных печатных символов существуют ещё и управляющие символы. Каждый раз когда вы нажимаете клавишу энтер при печати текста, вы вставляете невидимый управляющий символ конца строки. В операционных системах Windows конец строки обозначается двумя символами. Ребята из Microsoft любят отнимать место на вашем жестком диске. Это конечно шутка, просто старые принтеры требовали присутствия символа возврат печатающей каретки.

Большие буквы английского алфавита
Представление больших букв в кодировке ASCII

Семи лампочек достаточно для того чтобы закодировать английскую букву и некоторые другие дополнительные символы которые не имеют графического представления. Вместо лампочек для кодирования информации можно использовать все что угодно. Для представления информации можно применять какой-либо физический процесс из n состояний. Компьютер построен преимущественно из полупроводниковых элементов и поэтому состояний всего два. Один бит — 2^1 состояния, один байт (8 бит) — 2^8=256 состояний, два байта — 2^16=65536 состояний.

английский алфавит
Представление малых букв в кодировке ASCII

Впрочем, даже если вы применяете кодировку ASCII для представления символов, хранение одного символа требует 8 бит. Это объясняется размерами регистров центрального процессора, ведь так удобнее обрабатывать информацию. Если вам понравились анимированные иллюстрации и вы хотите распечатать плакат для компьютерного класса, тогда можете скачать его с сайта openclipart (poster1, poster2).

Восьмой бит в символах ASCII использован для представления символов других алфавитов и элементов псевдографики: черточки, угольники, кружочки и так далее. В операционных системах Windows подобные кодировки называются следующим образом: Windows-XXXX. Вместо символов XXXX употребляется номер закрепленный за каким-то из национальных алфавитов, или его вариаций. Кодировка Windows-1251 представляет символы русского алфавита. В операционных системах Linux эта кодировка называется CP-1251. CP — это английская аббревиатура «code page» (страница кодировки). Символы рассмотренных кодировок имеют размер 1 байт.

Недостатки и преимущества однобайтовых кодировок

Кодировка — это таблица интерпретации состояний. Поскольку восьмой бит использован, то для представления символов других алфавитов осталось 7-бит. Следовательно, возможно представить 2^7=128 символов, букв и знаков. Представьте, что вы живете в Камбодже и в вашем алфавите 74 буквы. Кроме них, присутствуют ещё и другие символы и знаки которые также надо представить. Совершенно ясно что одного байта не хватит.

Некоторые страны такие как Чехия, Словакия, Венгрия, Польша, Румыния используют кодировку Window-1250 для однобайтовых символов. Если русскоязычный пользователь захочет посмотреть румынский сайт который применяет данную кодировку для представления символов, тогда он увидит на экране бессмыслицу не содержащую румынских символов. Скорее всего данная бессмыслица будет интерпретирована браузером, как кодировка Windows-1251.

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

И тем не менее, их все ещё применяют. Так средство управления базами данных СУБД IBM DB2 позволяет определить однобайтовые кодировки для текстовых полей (Windows-1251, Windows-1250 и другие). Другие СУБД также позволяют сделать подобные вещи. Основное преимущество однобайтовых кодировок это размер одного символа. Это позволяет эффективно распоряжаться местом для хранения информации, особенно когда текстовых данных очень много. Однако, это не применяется в сфере управления государственными объектами. Не секрет, что все страны обмениваются информацией между собой. Есть специальные комиссии при ООН которые отвечают за сбор статистической информации. Например, комиссия по торговле — UN Comtrade.

Кроме всего вышесказанного, существуют Open Data проекты для реализации прозрачного управления государством. Смысл данных проектов в том, что каждый гражданин может видеть как происходит принятие решений каждым конкретным чиновником и если его не устраивает управленческие решения, отстранить его от управления. Согласно требованиям ISO и ICAO компьютерные сети и системы которые реализуют решение задач подобного рода должны хранить информацию в кодировке Unicode.

Unicode и его преимущества

Для того чтобы не переключатся между кодовыми страницами был придуман стандарт Unicode. Unicode консорциум отвечает за его развитие. Самым популярным, сейчас является способ представления символов Unicode — UTF-8. Для эффективного хранения данных он использует разный размер для символов и букв: 1 байт, 2 байта, 3 байта и 4 байта. Этот стандарт совместим со стандартом ASСII. Первые 128 символов это английские буквы, цифры, пунктуационные символы и управляющие знаки которые мы рассмотрели в самом начале. Каждая буква в русском, белорусском, польском и многих других языках имеет размер два байта. Это значит что для 4096 символов английского алфавита англичанин потратит 4 Кб, а жители других стран потратят 8 Кб памяти. Не обижайтесь, просто продолжайте жить дальше.

Двух байтов памяти достаточно, чтобы представить 65536 разных символов. Во множество таких символов включены алфавиты большинства языков мира и специфические знаки такие как: армянский знак вечности аревахач, стрелочки, математические символы и так далее. Редкие и не часто употребляемые символы имеют размер 3 байта. Во множество таких символов входит: значок «№», редкие китайские иероглифы, славянский астериск, кириллическая многоглазая буква «о (ꙮ)», и символы древнего славянского языка. Эмоджы, руны и дополнительные знаки имеют размер 4 байта. А вот это уже очень печально. Хранение текста состоящего из 4096 рун потребует наличия 16 Кб, это в 4 раза больше чем для английского текста!!!

Как компьютер интерпретирует символы Unicode?

Как браузер и другие приложения знают сколько байт занимает символ? Приложения обрабатывает символы байт за байтом. Если первый байт имеет числовое значение больше 192 (то есть, если два значащие биты слева в первом байте равны 1), тогда символ представляется двумя байтами и два значащих бита во втором байте равны 10. Если в значащих битах три единицы, тогда символ состоит из трех байт. Таблица описывающая принцип интерпретации Unicode представлена ниже.

Количество
байт
Шаблон
10XXXXXXX
211XXXXXX 10XXXXXX
3111XXXXX 10XXXXXX 10XXXXXX
41111XXXX 10XXXXXX 10XXXXXX 10XXXXXX

Вместо буквы «X» можно ставить 1, или 0. В самом начале, стандарт Unicode позволял использовать символы размером 6 байт (6 двоичных октетов)[1].

В 2003 году ситуация изменилась и для пользовательских нужд разрешают использовать только 4 октета. Этого вполне достаточно для всех мировых языков и даже для пиктограмм и символов Эмоджи. Возможно, в далеком будущем количество Эмоджи увеличится и у каждого человека будет свои собственные символы Эмоджи, тогда 6 октетов будут очень кстати [2].

Недостатки Unicode и алгоритм быстрого поиска

Чем больше байт информации, тем сложнее и медленнее происходит поиск. Члены сообществ по разработке стандартов RFC продумали все возможные трудности и нашли эффективное решение. Алгоритм Бойера-Мура (эвристика плохих символов) позволяет быстро находить текстовую информацию выраженную через символы Unicode. Именно этот алгоритм применяет ваш браузер при нажатии Ctrl+F. В научные интересы Бойера-Мура входило исследование и построение конечных цифровых автоматов.

Пусть длинна текста в котором осуществляется поиск равна N, а длинна шаблона для поиска равна M. Фаза предварительных вычислений займет O(M^2 + σ) операций, где σ — размер алфавита. Тогда в самом лучшем случае выполнение алгоритма займет O(N/M) сравнений. В самом худшем случае, когда текст состоит из одинаковых символов, например 100 букв «С», в которых осуществляется поиск 5 букв «С», тогда работа алгоритма займет O(N*M) сравнений.

В отношении безопасности, очень важно избегать ошибок переполнения буфера. В 2001 году были случаи использования запрещенных последовательностей октетов и неправильные парсеры привели к серьезным проблемам в безопасности. Поэтому при написании своего обработчика символов Unicode обратите внимание на стандарт RFC [RFC 3629, пункт 10].

Язык программирования и кодировки

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

  1. Отсутствует поддержка Unicode;
  2. Выбранный шрифт не имеет графического представления для данного символа.

Случаев когда поддержка Unicode отсутствует практически нет. Все языки программирования и современные приложения по умолчанию поддерживают такую кодировку. Но не все шрифты имеют графическое представление для пиктограмм и символов Эмоджи. Это следует учитывать при разработке программ для работы с текстовыми данными.

Применение кодировщиков в Python и модуль Encodings

Python это кроссплатформенный язык портированный под Windows, Macos, Android. В большинстве дистрибутивов Linux он установлен по умолчанию. В ОС Виндовс, запустите Python Idle, чтобы воспользоватся интерпретатором. Также можете установить интегрированную среду разработки Visual Studio Community, или PyCharm, чтобы упростить разработку на данном языке программирования. С точки зрения удобства использования, язык Python занимает первое место. Его используют ученые, сетевые инженеры и просто энтузиасты. Он прост и его можно применять пошагово в режиме интерпретации. Для просмотра справки для модуля Encodings непосредственно из режима интерпретации по очереди введите две строки.

  1. import encodings
  2. help(encodings)

Если вы решили создать собственный кодек, прочитайте также справку по модулю codecs. Импортируйте модуль codecs и также воспользуйтесь методом help(). Можно создать свой собственный кодек и зарегистрировать особый метод для поиска информации. Чтобы просмотреть список всех доступных методов (функций) модуля, введите команду dir(encodings). Будьте внимательны, если вы не ввели директиву «import название_модуля», тогда метод dir возвратит ошибку:

NameError: name ‘encodings’ is not defined

Во многих языках есть функция ord(), которая позволяет узнать код символа в десятичной системе исчисления. Получить коды для множества символов, а не для одного символа, можно используя кодеки. Для шестнадцатиричного представления примените кодек «hex_codec», как на рисунке снизу.

кодеки в python
Применение кодировщиков в Python

Этот кодировщик получил в качестве аргумента строку которая состоит из 5 начальных букв английского алфавита и 5 начальных букв русского алфавита. Узнать длину данной строки можно функцией len(), только значение нужно разделить на 2, поскольку один двоичный октет представляется двумя шестнадцатиричными цифрами (от 0 до ‘f’). Как вы видите, длинна такой строки 15 байт: 5 байтов английских букв и 10 байтов русских букв. Обратите внимание, что первый байт в русских символах «d0» и английская буква «A» отличается числовым значением от русской буквы «А». Метод int() преобразовал шестнадцатиричное значение для английской буквы «A» в десятичное 65. Для конвертации в двоичную систему исчисления примените функцию bin().

5 английских букв (41-45) и 5 русских букв (80-84) в кодировке CP-866

Важное замечание! После копирования текста из приложения которое сохраняет файлы в формате Windows-XXXX (CP-XXXX) в интерпретатор Python, он автоматически конвертирует текст в UTF-8. Если вы хотите узнать коды символов в других кодировках возьмите утилиту hexdump (подойдет любой другой шестнадцатиричный редактор) и откройте файл сохраненный в другой кодировке, например в CP-866, как на рисунке выше.

Кодировщик punycode позволяет передать Unicode посредством ASCII символов. Закодированной строке вы можете придать первоначальный вид применив метод decode(). Для выхода из режима интерпретации наберите функцию quit().

Итеративные и инкрементальные кодеки

Существуют два вида кодировщиков: итеративные кодировщики и инкрементальные кодировщики. Если кодировщик обрабатывает символы длинна которых заранее известна, тогда он называется итеративным. К такому типу кодировщиков относятся кодировщик: ASCII и другие типы кодировщиков основанные на нем, например ROT-13. Пример применения кодировщика ROT-13 показан на рисунке ниже.

итеративный кодек rot-13
Использование кодировщика Rot-13 в Python

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

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

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

Base64, Big5 и обезьяны на Youtube

Знаете ли вы, что любую программу можно передать в виде текста? Некоторые сайты запрещают загружать исполняемые файлы в формате *.EXE, или бинарные файлы. Некоторые почтовые клиенты, могут не пропускать письма с вложенными исполняемыми файлами. Во избежание этого вы можете преобразовать содержимое исполняемого файла в текст, алфавит которого составляет 64 символа ASCII. Данная кодировка получила название Base64. Размер закодированного таким образом файла будет больше, чем размер оригинального исполняемого файла.

Base64 сообщение
Обезьяны на Youtube

С использованием Base64 связаны некоторые смешные моменты. Если вы пользуетесь Youtube, тогда вы могли видеть ошибку изображенную на рисунке выше. Как вы видите, это очень похоже на кодировку Base64, но отсутствует символ слеша и плюс. Кодировка Base64 существует в нескольких вариантах. На рисунке выше, изображена «urlsafe Base64» кодировка. Символы 62 и 63 («+» и «/») изменены на «-» и «_». После применения кодека Base64, вы можете получить зашифрованное содержимое стэка вашего браузера. Смешная обезьянка, на картинке выше, провоцирует поделится данным скриншотом с друзьями и добавить хэштег #youtubemonkeys. Не спешите смеяться, это не самоирония. Инженеры Youtube регулярно осуществляют поиск подобных скриншотов. Декодируют base64 и потом, расшифровывают секретное содержимое стэка вашего браузера и находят неисправность. Если бы они вас попросили поделится содержимым стэка, вы бы наверняка отказались. Не правда, ли?

Для передачи китайских письма, иногда не достаточно стандартных иероглифов. В Гонг Конге применяют дополнительные иероглифы. Для их ввода изобрели кодировку Big5. Кроме этой кодировки Python поддерживает и другие экзотические кодировки, которые входят в стандарты ISO [3].

Выводы

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

Некоторые буквы имеют одинаковую форму, но различный код. Эта особенность может быть использована для стеганографических целей. Мы рассмотрели, каким способом вы можете узнать код буквы: 1) посредством использования языка программирования Python; 2) посредством утилиты hexdump.

Источники информации:

[1] RFC 2279, «UTF-8, a transformation format of ISO 10646», устаревшая версия.
[2] RFC 3629, «UTF-8, a transformation format of ISO 10646».
[3] ISO 10646, Стандарт Unicode.

Оставьте комментарий

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