Что такое кодировка unicode информатика: Юникод — Википедия – Что такое Юникод? — Таблица символов Юникода®

Любые числа (в определенных пределах) в памяти компьютера кодируются числами двоичной системы счисления. Для этого существуют простые и понятные правила перевода. Однако на сегодняшний день компьютер используется куда шире, чем в роли исполнителя трудоемких вычислений. Например, в памяти ЭВМ хранятся текстовая и мультимедийная информация. Поэтому возникает первый вопрос:

Содержание

Как в памяти компьютера хранятся символы (буквы)?

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

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

Однако алфавитов в мире очень много (английский, русский, китайский и др.). Поэтому следующий вопрос:

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

Для ответа на этот вопрос пойдем историческим путем.

В 60-х годах XX века в американском национальном институте стандартизации (ANSI) была разработана таблица кодирования символов, которая впоследствии была использована во всех операционных системах. Эта таблица называется ASCII (American Standard Code for Information Interchange – американский стандартный код для обмена информацией). Чуть позже появилась расширенная версия ASCII.

В соответствие с таблицей кодирования ASCII для представления одного символа выделяется 1 байт (8 бит). Набор из 8 ячеек может принять 2

8 = 256 различных значений. Первые 128 значений (от 0 до 127) постоянны и формируют так называемую основную часть таблицы, куда входят десятичные цифры, буквы латинского алфавита (заглавные и строчные), знаки препинания (точка, запятая, скобки и др.), а также пробел и различные служебные символы (табуляция, перевод строки и др.). Значения от 128 до 255 формируют дополнительную часть таблицы, где принято кодировать символы национальных алфавитов.

Поскольку национальных алфавитов огромное множество, то расширенные ASCII-таблицы существуют во множестве вариантов. Даже для русского языка существуют несколько таблиц кодирования (распространены Windows-1251 и Koi8-r). Все это создает дополнительные трудности. Например, мы отправляем письмо, написанное в одной кодировке, а получатель пытается прочитать ее в другой. В результате видит кракозябры. Поэтому читающему требуется применить для текста другую таблицу кодирования.

Есть и другая проблема. В алфавитах некоторых языков слишком много символов и они не помещаются в отведенные им позиции с 128 до 255 однобайтовой кодировки.

Третья проблема — что делать, если в тексте используется несколько языков (например, русский, английский и французский)? Нельзя же использовать две таблицы сразу …

Чтобы решить эти проблемы одним разом была разработана кодировка Unicode.

Стандарт кодирования символов Unicode

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

В Unicode для кодирования символов предоставляется 31 бит (4 байта за вычетом одного бита). Количество возможных комбинаций дает запредельное число: 231 = 2 147 483 684 (т.е. более двух миллиардов). Поэтому Unicode описывает алфавиты всех известных языков, даже «мертвых» и выдуманных, включает многие математические и иные специальные символы. Однако информационная емкость 31-битового Unicode все равно остается слишком большой. Поэтому чаще используется сокращенная 16-битовая версия (2

16 = 65 536 значений), где кодируются все современные алфавиты.

В Unicode первые 128 кодов совпадают с таблицей ASCII.

Что такое Юникод? — Таблица символов Юникода®

Главная → Статьи → Юникод → Что такое Юникод?

Юникод (Unicode), это многоязычный, основанный на ASCII стандарт кодирования символов, а также, связанное с ним, семейство многобайтных кодировок. Если некоторые слова из предыдущего предложения вам не понятны, давайте рассмотрим их подробнее.

Что такое кодировка

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

Поэтому программистам при работе с текстом приходится делать подобные соглашения: «А давайте каждому символу будет соответствовать один байт. Причём, если в байте будет число 43, то будем считать, что это цифра ноль. А если число 66, то пусть это будет заглавная латинская буква B».

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

Крякозябры

Наверное, часто бывала ситуация, когда вы открываете страницу в браузере, а там вместо текста какая-то мешанина из чудных символов. Или просто сплошные вопросительные знаки. Или вы пишете любовное письмо своей девушке, а она звонит вам и говорит «что за нечитаемый бред ты мне прислал? Я обиделась».

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

Например, ваш текстовый редактор настроен на кодировку Windows-1251. И вы пишете «Здравствуйте, дорогая Маша!». Вы нажимаете первую букву и программа думает: «ага, русская заглавная буква Зэ — код 199». И записывает число 199 в файл. Маша получает ваше письмо, но в её почтовом клиенте стоит кодировка KOI8-R (потому что Маша любит старый Unix). А в этой кодировке числу 199 соответствует строчная буква «г». И Маша читает: «гДПЮБЯРБСИРЕ, ДНПНЦЮЪ лЮЬЮ!». Маша обиделась!

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

<meta http-equiv="content-type" content="text/html; charset=windows-1251" />

ASCII

В определённый момент времени распространение получила кодировка ASCII (American Standard Code for Information Interchange). В ней определены 128 символов с кодами от 0 до 127. Сюда включён латинский алфавит, цифры и основные знаки препинания (Основная латиница), а также Управляющие символы.

Практически все современные кодировки, использующиеся на персональных компьютерах являются ASCII-совместимыми. То есть первые 128 символов у них кодируются одинаково, а различия начинаются с кода 128 и выше. Вышеупомянутые Windows-1251 и KOI8-r также основаны на ASCII и если бы письмо начиналось бы с «Hello, my dear Maria!», то недопонимания не возникло бы.

Основан на ASCII и Юникод.

Однобайтные кодировки

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

Однобайтные кодировки всем хороши: они компактны, с ними легко работать (нужно достать пятый символ — просто берём пятый байт от начала). Единственная проблема: в них помещается мало символов. Ровно столько, сколько значений может принимать один байт, то есть обычно, это 256. Например, в Windows-1251 мы отдали 128 символов под ASCII, добавили 66 букв русского алфавита (строчные и заглавные), несколько знаков препинания и вот у нас уже остаётся не так много свободных позиций. Даже на псевдографику не хватает.

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

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

Многобайтные кодировки

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

  • Для всех возможных символов, иероглифов и смайликов даже 65 тысяч символов мало.
  • Текстовые файлы стали занимать вдвое больше места, даже тексты на английском. Слишком расточительно.
  • Кодировки перестали быть ASCII-совместимыми и многие программы не могли с ними работать.

Стандарт Unicode

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

С одной стороны, Юникод позволяет кодировать практически неограниченное количество символов. В последнем стандарте определено более 100 000 различных символов всех современных и многих уже мёртвых языков, а также различные иконки и пиктограммы. С другой стороны, некоторые способы кодирования позволяют Юникоду оставаться ASCII-совместимыми. Что позволяет работать, как и раньше многим программам, а также американским и другим англоязычным пользователям, многие из которых появления Юникода даже не заметили. В Юникоде также собраны все символы из всех популярных стандартов кодирования, что позволяет преобразовать в него любой текст из старой кодировки.

Практически все современные программы, работающие с текстом, понимают Юникод. Более того, обычно они в нём и работают. Например, даже когда вы открываете сайт в старой доброй Windows-1251, браузер сначала внутри у себя перекодирует все тексты в Юникод, а потом отображает их. В общем, Юникод, это светлое будущее интернета и всей компьютерной индустрии.

Отличие набора символов от кодировки

Термины «кодировка», «стандарт кодирования», «набор символов» обычно используются, как синонимы, но между ними есть и тонкие различия. Важно понимать разницу между «стандартом» и, собственно, «кодировкой». Некий стандарт просто говорит, что буква «A», это число 65, а буква «B» — 66. Кодировка же отвечает за то, как эти числа представить в памяти компьютера.

В эпоху однобайтных кодировок, это различие было практически неуловимо. Число 65 — байт со значением 65 или последовательность битов 01000001. Для многобайтных же уже возникают вопросы: сколько байтов использовать, в каком порядке, фиксированное число байтов или нет?

То есть в стандарте Юникода определено, что кириллической букве «А» соответствует абстрактное число 1040. Как представить это число в виде последовательности байтов решает уже конкретная кодировка — UTF-8, UTF-16, UTF-32.

То есть текстовый файл не может быть в кодировке «Юникод», а только в конкретной кодировке «UTF-8» или «UTF-16».

Кодировки и шрифты

Юникод, как и любая другая кодировка не описывает того, как следует отрисовывать символы. Для него число 1040, это «кириллическая заглавная буква А». А какая она, печатная, прописная, наклонная, жирная или с завитушками, это не его дело.

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

Подробнее это описано в статье почему у меня не отображаются некоторые символы?

Юникод для чайников / Habr


Сам я не очень люблю заголовки вроде «Покемоны в собственном соку для чайников\кастрюль\сковородок», но это кажется именно тот случай — говорить будем о базовых вещах, работа с которыми довольно часто приводить к купе набитых шишек и уйме потерянного времени вокруг вопроса — «Почему же оно не работает?». Если вы до сих пор боитесь и\или не понимаете Юникода — прошу под кат.
Зачем?

Главный вопрос новичка, который встречается с впечатляющим количеством кодировок и на первый взгляд запутанными механизмами работы с ними (например, в Python 2.x). Краткий ответ — потому что так сложилось 🙂

Кодировкой, кто не знает, называют способ представления в памяти компьютера (читай — в нулях-единицах\числах) цифр, буков и всех остальных знаков. Например, пробел представляется как 0b100000 (в двоичной), 32 (в десятичной) или 0x20 (в шестнадцатеричной системе счисления).

Так вот, когда-то памяти было совсем немного и всем компьютерам было достаточно 7 бит для представления всех нужных символов (цифры, строчный\прописной латинский алфавит, куча знаков и так называемые управляемые символы — все возможные 127 номеров были кому-то отданы). Кодировка в это время была одна — ASCII. Шло время, все были счастливы, а кто не был счастлив (читай — кому не хватало знака «©» или родной буквы «щ») — использовали оставшиеся 128 знаков на свое усмотрение, то есть создавали новые кодировки. Так появились и ISO-8859-1, и наши (то есть кириличные) cp1251 и KOI8. Вместе с ними появилась и проблема интерпретации байтов типа 0b1******* (то есть символов\чисел от 128 и до 255) — например, 0b11011111 в кодировке cp1251 это наша родная «Я», в тоже время в кодировке ISO-8859-1 это греческая немецкая Eszett (подсказывает Moonrise) «ß». Ожидаемо, сетевая коммуникация и просто обмен файлами между разными компьютерами превратились в чёрт-знает-что, несмотря на то, что заголовки типа ‘Content-Encoding’ в HTTP протоколе, email-письмах и HTML-страницах немного спасали ситуацию.

В этот момент собрались светлые умы и предложили новый стандарт — Unicode. Это именно стандарт, а не кодировка — сам по себе Юникод не определяет, как символы будут сохранятся на жестком диске или передаваться по сети. Он лишь определяет связь между символом и некоторым числом, а формат, согласно с которым эти числа будут превращаться в байты, определяется Юникод-кодировками (например, UTF-8 или UTF-16). На данный момент в Юникод-стандарте есть немного более 100 тысяч символов, тогда как UTF-16 позволяет поддерживать более одного миллиона (UTF-8 — и того больше).

Полней и веселей по теме советую почитать у великолепного Джоеля Спольски The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets.

Ближе к делу!

Естественно, есть поддержка Юникода и в Пайтоне. Но, к сожалению, только в Python 3 все строки стали юникодом, и новичкам приходиться убиваться об ошибки типа:
>>> with open('1.txt') as fh:
	s = fh.read()

>>> print s
кощей
>>> parser_result = u'баба-яга'  # присвоение для наглядности, представим себе, что это результат работы какого-то парсера
>>> parser_result + s
Traceback (most recent call last):
  File "<pyshell#43>", line 1, in <module>
    parser_result + s
UnicodeDecodeError: 'ascii' codec can't decode byte 0xea in position 0: ordinal not in range(128)

или так:
>>> str(parser_result)
Traceback (most recent call last):
  File "<pyshell#52>", line 1, in <module>
    str(parser_result)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)

Давайте разберемся, но по порядку.
Зачем кто-то использует Юникод?

Почему мой любимый html-парсер возвращает Юникод? Пусть возвращает обычную строку, а я там уже с ней разберусь! Верно? Не совсем. Хотя каждый из существующих в Юникоде символов и можно (наверное) представить в некоторой однобайтовой кодировке (ISO-8859-1, cp1251 и другие называют однобайтовыми, поскольку любой символ они кодируют ровно в один байт), но что делать если в строке должны быть символы с разных кодировок? Присваивать отдельную кодировку каждому символу? Нет, конечно, надо использовать Юникод.
Зачем нам новый тип «unicode»?

Вот мы и добрались до самого интересного. Что такое строка в Python 2.x? Это просто байты. Просто бинарные данные, которые могут быть чем-угодно. На самом деле, когда мы пишем что-нибудь вроде:
>>> x = 'abcd'
>>> x
'abcd'
интерпретатор не создает переменную, которая содержит первые четыре буквы латинского алфавита, но только последовательность
('a', 'b', 'c', 'd')
с четырёх байт, и латинские буквы здесь используются исключительно для обозначения именно этого значения байта. То есть ‘a’ здесь просто синоним для написания ‘\x61’, и ни чуточку больше. Например:
>>> '\x61' 
'a'
>>> struct.unpack('>4b', x)  # 'x' - это просто четыре signed/unsigned char-а
(97, 98, 99, 100)
>>> struct.unpack('>2h', x)  # или два short-а
(24930, 25444)
>>> struct.unpack('>l', x)  # или один long
(1633837924,)
>>> struct.unpack('>f', x)  # или float
(2.6100787562286154e+20,)
>>> struct.unpack('>d', x * 2)   # ну или половинка double-а
(1.2926117739473244e+161,)

И всё!

И ответ на вопрос — зачем нам «unicode» уже более очевиден — нужен тип, который будет представятся символами, а не байтами.

Хорошо, я понял чем есть строка. Тогда что такое Юникод в Пайтоне?

«type unicode» — это прежде всего абстракция, которая реализует идею Юникода (набор символов и связанных с ними чисел). Объект типа «unicode» — это уже не последовательность байт, но последовательность собственно символов без какого либо представления о том, как эти символы эффективно сохранить в памяти компьютера. Если хотите — это более высокой уровень абстракции, чем байтовый строки (именно так в Python 3 называют обычные строки, которые используются в Python 2.6).
Как пользоваться Юникодом?

Юникод-строку в Python 2.6 можно создать тремя (как минимум, естественно) способами:
  • u»» литерал:
    >>> u'abc'
    u'abc'
    

  • Метод «decode» для байтовой строки:
    >>> 'abc'.decode('ascii')
    u'abc'
    

  • Функция «unicode»:
    >>> unicode('abc', 'ascii')
    u'abc'
    

ascii в последних двух примерах указывается в качестве кодировки, что будет использоваться для превращения байтов в символы. Этапы этого превращения выглядят примерно так:
'\x61' -> кодировка ascii -> строчная латинская "a" -> u'\u0061' (unicode-point для этой буквы)

или

'\xe0' -> кодировка c1251 -> строчная кириличная "a" -> u'\u0430'

Как из юникод-строки получить обычную? Закодировать её:

>>> u'abc'.encode('ascii')
'abc'

Алгоритм кодирования естественно обратный приведенному выше.

Запоминаем и не путаем — юникод == символы, строка == байты, и байты -> что-то значащее (символы) — это де-кодирование (decode), а символы -> байты — кодирование (encode).

Не кодируется 🙁

Разберем примеры с начала статьи. Как работает конкатенация строки и юникод-строки? Простая строка должна быть превращена в юникод-строку, и поскольку интерпретатор не знает кодировки, от использует кодировку по умолчанию — ascii. Если этой кодировке не удастся декодировать строку, получим некрасивую ошибку. В таком случае нам нужно самим привести строку к юникод-строке, используя правильную кодировку:
>>> print type(parser_result), parser_result
<type 'unicode'> баба-яга
>>> s = 'кощей'
>>> parser_result + s
Traceback (most recent call last):
  File "<pyshell#67>", line 1, in <module>
    parser_result + s
UnicodeDecodeError: 'ascii' codec can't decode byte 0xea in position 0: ordinal not in range(128)
>>> parser_result + s.decode('cp1251')
u'\xe1\xe0\xe1\xe0-\xff\xe3\xe0\u043a\u043e\u0449\u0435\u0439'
>>> print parser_result + s.decode('cp1251')
баба-ягакощей
>>> print '&'.join((parser_result, s.decode('cp1251')))
баба-яга&кощей   # Так лучше :)

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

Теперь использование «str» и юникод-строк. Не используйте «str» и юникод строки 🙂 В «str» нет возможности указать кодировку, соответственно кодировка по умолчанию будет использоваться всегда и любые символы > 128 будут приводить к ошибке. Используйте метод «encode»:

>>> print type(s), s
<type 'unicode'> кощей
>>> str(s)
Traceback (most recent call last):
  File "<pyshell#90>", line 1, in <module>
    str(s)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-4: ordinal not in range(128)
>>> s = s.encode('cp1251')
>>> print type(s), s
<type 'str'> кощей

«UnicodeEncodeError» — знак того, что нам нужно указать правильную кодировку во время превращения юникод-строки в обычную (или использовать второй параметр ‘ignore’\’replace’\’xmlcharrefreplace’ в методе «encode»).

Хочу ещё!

Хорошо, используем бабу-ягу из примера выше ещё раз:
>>> parser_result = u'баба-яга'   #1
>>> parser_result
u'\xe1\xe0\xe1\xe0-\xff\xe3\xe0'   #2
>>> print parser_result
áàáà-ÿãà   #3
>>> print parser_result.encode('latin1')  #4
баба-яга
>>> print parser_result.encode('latin1').decode('cp1251')  #5
баба-яга
>>> print unicode('баба-яга', 'cp1251')   #6
баба-яга

Пример не совсем простой, но тут есть всё (ну или почти всё). Что здесь происходит:
  1. Что имеем на входе? Байты, которые IDLE передает интерпретатору. Что нужно на выходе? Юникод, то есть символы. Осталось байты превратить в символы — но ведь надо кодировку, правда? Какая кодировка будет использована? Смотрим дальше.
  2. Здесь важной момент:
    >>> 'баба-яга'
    '\xe1\xe0\xe1\xe0-\xff\xe3\xe0'
    >>> u'\u00e1\u00e0\u00e1\u00e0-\u00ff\u00e3\u00e0' == u'\xe1\xe0\xe1\xe0-\xff\xe3\xe0'
    True
    
    как видим, Пайтон не заморачивается с выбором кодировки — байты просто превращаются в юникод-поинты:
    >>> ord('а')
    224
    >>> ord(u'а')
    224
    
  3. Только вот проблема — 224-ый символ в cp1251 (кодировка, которая используется интерпретатором) совсем не тот, что 224 в Юникоде. Именно из-за этого получаем кракозябры при попытке напечатать нашу юникод-строку.
  4. Как помочь бабе? Оказывается, что первые 256 символов Юникода те же, что и в кодировке ISO-8859-1\latin1, соответственно, если используем её для кодировки юникод-строки, получим те байты, которые вводили сами (кому интересно — Objects/unicodeobject.c, ищем определение функции «unicode_encode_ucs1»):
    >>> parser_result.encode('latin1')
    '\xe1\xe0\xe1\xe0-\xff\xe3\xe0'
    
  5. Как же получить бабу в юникоде? Надо указать, какую кодировку использовать:
    >>> parser_result.encode('latin1').decode('cp1251')
    u'\u0431\u0430\u0431\u0430-\u044f\u0433\u0430'
    
  6. Способ с пункта #5 конечно не ахти, намного удобней использовать использовать built-in unicode.
На самом деле не всё так плохо с «u»» литералами, поскольку проблема возникает только в консоле. Ведь в случае использования non-ascii символов в исходном файле Пайтон будет настаивать на использовании заголовка типа «# -*- coding: -*-» (PEP 0263), и юникод-строки будут использовать правильную кодировку.

Есть ещё способ использования «u»» для представления, например, кириллицы, и при этом не указывать кодировку или нечитабельные юникод-поинты (то есть «u’\u1234’»). Способ не совсем удобный, но интересный — использовать unicode entity codes:

>>> s = u'\N{CYRILLIC SMALL LETTER KA}\N{CYRILLIC SMALL LETTER O}\N{CYRILLIC SMALL LETTER SHCHA}\N{CYRILLIC SMALL LETTER IE}\N{CYRILLIC SMALL LETTER SHORT I}'
>>> print s
кощей

Ну и вроде всё. Основные советы — не путать «encode»\«decode» и понимать различия между байтами и символами.

Python 3

Здесь без кода, ибо опыта нет. Свидетели утверждают, что там всё значительно проще и веселее. Кто возьмется на кошках продемонстрировать различия между здесь (Python 2.x) и там (Python 3.x) — респект и уважуха.
Полезно

Раз уж мы о кодировках, порекомендую ресурс, который время-от-времени помогает побороть кракозябры — http://2cyr.com/decode/?lang=ru.

Ещё раз линк на статью Спольски — The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets.

Unicode HOWTO — официальный документ о том где, как и зачем Юникод в Python 2.x.

Спасибо за внимание. Буду благодарен за замечания в приват.

P.S. Подкинули линк на перевод Спольски — Абсолютный Минимум, который Каждый Разработчик Программного Обеспечения Обязательно Должен Знать о Unicode и Наборах Символов.

Как работают кодировки текста. Откуда появляются «кракозябры». Принципы кодирования. Обобщение и детальный разбор

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

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

О чем будет под катом: принцип работы одно байтовых кодировок (ASCII, Windows-1251 и т.д.), предпосылки появления Unicode, что такое Unicode, Unicode-кодировки UTF-8, UTF-16, их отличия, принципиальные особенности, совместимость и несовместимость разных кодировок, принципы кодирования символов, практический разбор кодирования и декодирования.

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

Предпосылки Unicode


Начать думаю стоит с того времени когда компьютеризация еще не была так сильно развита и только набирала обороты. Тогда разработчики и стандартизаторы еще не думали, что компьютеры и интернет наберут такую огромную популярность и распространенность. Собственно тогда то и возникла потребность в кодировке текста. В каком то же виде нужно было хранить буквы в компьютере, а он (компьютер) только единицы и нули понимает. Так была разработана одно-байтовая кодировка ASCII (скорее всего она не первая кодировка, но она наиболее распространенная и показательная, по этому ее будем считать за эталонную). Что она из себя представляет? Каждый символ в этой кодировке закодирован 8-ю битами. Несложно посчитать что исходя из этого кодировка может содержать 256 символов (восемь бит, нулей или единиц 28=256).

Первые 7 бит (128 символов 27=128) в этой кодировке были отданы под символы латинского алфавита, управляющие символы (такие как переносы строк, табуляция и т.д.) и грамматические символы. Остальные отводились под национальные языки. То есть получилось что первые 128 символов всегда одинаковые, а если хочешь закодировать свой родной язык пожалуйста, используй оставшуюся емкость. Собственно так и появился огромный зоопарк национальных кодировок. И теперь сами можете представить, вот например я находясь в России беру и создаю текстовый документ, у меня по умолчанию он создается в кодировке Windows-1251 (русская кодировка использующаяся в ОС Windows) и отсылаю его кому то, например в США. Даже то что мой собеседник знает русский язык, ему не поможет, потому что открыв мой документ на своем компьютере (в редакторе с дефолтной кодировкой той же самой ASCII) он увидит не русские буквы, а кракозябры. Если быть точнее, то те места в документе которые я напишу на английском отобразятся без проблем, потому что первые 128 символов кодировок Windows-1251 и ASCII одинаковые, но вот там где я написал русский текст, если он в своем редакторе не укажет правильную кодировку будут в виде кракозябр.

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

Небольшой практикум ASCII


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

Вот таблица символов ASCII:

Тут имеем 3 колонки:

  • номер символа в десятичном формате
  • номер символа в шестнадцатиричном формате
  • представление самого символа.

Итак, закодируем строку «ok» (англ.) в кодировке ASCII. Символ «o» (англ.) имеет позицию 111 в десятичном виде и 6F в шестнадцатиричном. Переведем это в двоичную систему — 01101111. Символ «k» (англ.) — позиция 107 в десятеричной и 6B в шестнадцатиричной, переводим в двоичную — 01101011. Итого строка «ok» закодированная в ASCII будет выглядеть так — 01101111 01101011. Процесс декодирования будет обратный. Берем по 8 бит, переводим их в 10-ичную кодировку, получаем номер символа, смотрим по таблице что это за символ.

Unicode


С предпосылками создания общей таблицы для всех в мире символов, разобрались. Теперь собственно, к самой таблице. Unicode — именно эта таблица и есть (это не кодировка, а именно таблица символов). Она состоит из 1 114 112 позиций. Большинство этих позиций пока не заполнены символами, так что вряд ли понадобится это пространство расширять.

Разделено это общее пространство на 17 блоков, по 65 536 символов в каждом. Каждый блок содержит свою группу символов. Нулевой блок — базовый, там собраны наиболее употребляемые символы всех современных алфавитов. Во втором блоке находятся символы вымерших языков. Есть два блока отведенные под частное использование. Большинство блоков пока не заполнены.

Итого емкость символов юникода составляет от 0 до 10FFFF (в шестнадцатиричном виде).

Записываются символы в шестнадцатиричном виде с приставкой «U+». Например первый базовый блок включает в себя символы от U+0000 до U+FFFF (от 0 до 65 535), а последний семнадцатый блок от U+100000 до U+10FFFF (от 1 048 576 до 1 114 111).

Отлично теперь вместо зоопарка национальных кодировок, у нас есть всеобъемлющая таблица, в которой зашифрованы все символы которые нам могут пригодиться. Но тут тоже есть свои недостатки. Если раньше каждый символ был закодирован одним байтом, то теперь он может быть закодирован разным количеством байтов. Например для кодирования всех символов английского алфавита по прежнему достаточно одного байта например тот же символ «o» (англ.) имеет в юникоде номер U+006F, то есть тот же самый номер как и в ASCII — 6F в шестнадцатиричной и 111 в десятеричной. А вот для кодирования символа «U+103D5» (это древнеперсидская цифра сто) — 103D5 в шестнадцатиричной и 66 517 в десятеричной, тут нам потребуется уже три байта.

Решить эту проблему уже должны юникод-кодировки, такие как UTF-8 и UTF-16. Далее речь пойдет про них.

UTF-8


UTF-8 является юникод-кодировкой переменной длинны, с помощью которой можно представить любой символ юникода.

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

Немного отступлю от темы, надо написать про совместимость ASCII и UTF

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

Давайте возьмем символ «o»(англ.) из примера про ASCII выше. Помним что в таблице ASCII символов он находится на 111 позиции, в битовом виде это будет 01101111. В таблице юникода этот символ — U+006F что в битовом виде тоже будет 01101111. И теперь так, как UTF — это кодировка переменной длины, то в ней этот символ будет закодирован одним байтом. То есть представление данного символа в обеих кодировках будет одинаково. И так для всего диапазона символов от 0 до 128. То есть если ваш документ состоит из английского текста то вы не заметите разницы если откроете его и в кодировке UTF-8 и UTF-16 и ASCII (прим. в UTF-16 такие символы все равно будут закодированы двумя байтами, по этому вы не увидите разницы, если ваш редактор будет игнорировать нулевые байты), и так до момента пока вы не начнете работать с национальным алфавитом.

Сравним на практике как будет выглядеть фраза «Hello мир» в трех разных кодировках: Windows-1251 (русская кодировка), ISO-8859-1 (кодировка западно-европейских языков), UTF-8 (юникод-кодировка). Суть данного примера состоит в том что фраза написана на двух языках. Посмотрим как она будет выглядеть в разных кодировках.


В кодировке ISO-8859-1 нет таких символов «м», «и» и «р».

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

Будем считать что изначально фраза была записана в кодировке Windows-1251. Исходя из таблицы выше запишем эту фразу в двоичном виде, в кодировке Windows-1251. Для этого нам потребуется всего только перевести из десятеричной или шестнадцатиричной системы (из таблицы выше) символы в двоичную.

01001000 01100101 01101100 01101100 01101111 00100000 11101100 11101000 11110000
Отлично, вот это и есть фраза «Hello мир» в кодировке Windows-1251.

Теперь представим что вы имеете файл с текстом, но не знаете в какой кодировке этот текст. Вы предполагаете что он в кодировке ISO-8859-1 и открываете его в своем редакторе в этой кодировке. Как сказано выше с частью символов все в порядке, они есть в этой кодировке, и даже находятся на тех же местах, но вот с символами из слова «мир» все сложнее. Этих символов в этой кодировке нет, а на их местах в кодировке ISO-8859-1 находятся совершенно другие символы. А конкретно «м» — позиция 236, «и» — 232. «р» — 240. И на этих позициях в кодировке ISO-8859-1 находятся следующие символы позиция 236 — символ «ì», 232 — «è», 240 — «ð»

Значит фраза «Hello мир» закодированная в Windows-1251 и открытая в кодировке ISO-8859-1 будет выглядеть так: «Hello ìèð». Вот и получается что эти две кодировки совместимы лишь частично, и корректно перекодировать строку из одной кодировке в другую не получится, потому что там просто напросто нет таких символов.

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

Работает она следующим образом. Первый бит каждого байта кодирующего символ отвечает не за сам символ, а за определение байта. То есть например если ведущий (первый) бит нулевой, то это значит что для кодирования символа используется всего один байт. Что и обеспечивает совместимость с ASCII. Если внимательно посмотрите на таблицу символов ASCII то увидите что первые 128 символов (английский алфавит, управляющие символы и знаки препинания) если их привести к двоичному виду, все начинаются с нулевого бита (будьте внимательны, если будете переводить символы в двоичную систему с помощью например онлайн конвертера, то первый нулевой ведущий бит может быть отброшен, что может сбить с толку).

01001000 — первый бит ноль, значит 1 байт кодирует 1 символ -> «H»

01100101 — первый бит ноль, значит 1 байт кодирует 1 символ -> «e»

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

Для двухбайтовых символов первые три бита должны быть такие — 110

11010000 10111100 — в начале 110, значит 2 байта кодируют 1 символ. Второй байт в таком случае всегда начинается с 10. Итого отбрасываем управляющие биты (начальные, которые выделены красным и зеленым) и берем все оставшиеся (10000111100), переводим их в шестнадцатиричный вид (043С) -> U+043C в юникоде равно символ «м».

для трех-байтовых символов в первом байте ведущие биты — 1110

11101000 10000111 101010101 — суммируем все кроме управляющих битов и получаем что в 16-ричной равно 103В5, U+103D5 — древнеперситдская цифра сто (10000001111010101)

для четырех-байтовых символов в первом байте ведущие биты — 11110

11110100 10001111 10111111 10111111 — U+10FFFF это последний допустимый символ в таблице юникода (100001111111111111111)

Теперь, при желании, можем записать нашу фразу в кодировке UTF-8.

UTF-16


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

Начнем с символов которые кодируются одной кодовой парой. Легко посчитать что таких символов может быть 65 535 (2в16), что полностью совпадает с базовым блоком юникода. Все символы находящиеся в этом блоке юникода в кодировке UTF-16 будут закодированы одной кодовой парой (двумя байтами), тут все просто.

символ «o» (латиница) — 00000000 01101111
символ «M» (кириллица) — 00000100 00011100

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

Для начала введем понятия суррогатной пары. Суррогатная пара — это две кодовые пары используемые для кодирования одного символа (итого 4 байта). Для таких суррогатных пар в таблице юникода отведен специальный диапазон от D800 до DFFF. Это значит, что при преобразовании кодовой пары из байтового вида в шестнадцатиричный вы получаете число из этого диапазона, то перед вами не самостоятельный символ, а суррогатная пара.

Чтобы закодировать символ из диапазона 1000010FFFF (то есть символ для которого нужно использовать более одной кодовой пары) нужно:

  1. из кода символа вычесть 10000(шестнадцатиричное) (это наименьшее число из диапазона 1000010FFFF)
  2. в результате первого пункта будет получено число не больше FFFFF, занимающее до 20 бит
  3. ведущие 10 бит из полученного числа суммируются с D800 (начало диапазона суррогатных пар в юникоде)
  4. следующие 10 бит суммируются с DC00 (тоже число из диапазона суррогатных пар)
  5. после этого получатся 2 суррогатные пары по 16 бит, первые 6 бит в каждой такой паре отвечают за определение того что это суррогат,
  6. десятый бит в каждом суррогате отвечает за его порядок если это 1 то это первый суррогат, если 0, то второй

Разберем это на практике, думаю станет понятнее.

Для примера зашифруем символ, а потом расшифруем. Возьмем древнеперсидскую цифру сто (U+103D5):

  1. 103D510000 = 3D5
  2. 3D5 = 0000000000 1111010101 (ведущие 10 бит получились нулевые приведем это к шестнадцатиричному числу, получим 0 (первые десять), 3D5 (вторые десять))
  3. 0 + D800 = D800 (1101100000000000) первые 6 бит определяют что число из диапазона суррогатных пар десятый бит (справа) нулевой, значит это первый суррогат
  4. 3D5 + DC00 = DFD5 (1101111111010101) первые 6 бит определяют что число из диапазона суррогатных пар десятый бит (справа) единица, значит это второй суррогат
  5. итого данный символ в UTF-16 — 1101100000000000 1101111111010101

Теперь наоборот раскодируем. Допустим что у нас есть вот такой код — 1101100000100010 1101111010001000:
  1. переведем в шестнадцатиричный вид = D822 DE88 (оба значения из диапазона суррогатных пар, значит перед нами суррогатная пара)
  2. 1101100000100010 — десятый бит (справа) нулевой, значит первый суррогат
  3. 1101111010001000 — десятый бит (справа) единица, значит второй суррогат
  4. отбрасываем по 6 бит отвечающих за определение суррогата, получим 0000100010 1010001000 (8A88)
  5. прибавляем 10000 (меньшее число суррогатного диапазона) 8A88 + 10000 = 18A88
  6. смотрим в таблице юникода символ U+18A88 = Tangut Component-649. Компоненты тангутского письма.

Спасибо тем кто смог дочитать до конца, надеюсь было полезно и не очень занудно.

Вот некоторые интересные ссылки по данной теме:
habr.com/ru/post/158895 — полезные общие сведения по кодировкам
habr.com/ru/post/312642 — про юникод
unicode-table.com/ru — сама таблица юникод символов

Ну и собственно куда же без нее
ru.wikipedia.org/wiki/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4 — юникод
ru.wikipedia.org/wiki/ASCII — ASCII
ru.wikipedia.org/wiki/UTF-8 — UTF-8
ru.wikipedia.org/wiki/UTF-16 — UTF-16

Кодировка «Юникод»: стандарт кодирования символов

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

юникод что это

Определение

Кодировка «Юникод» — стандарт кодирования символов. Он был предложен некоммерческой организацией Unicode Inc. в 1991 году. Стандарт разработан с целью объединения как можно большего числа разнотипных символов в одном документе. Страница, которая создана на его основе, может содержать в себе буквы и иероглифы из разных языков (от русского до корейского) и математические знаки. При этом все символы в данной кодировке отображаются без проблем.

Причины создания

Когда-то, задолго до появления единой системы «Юникод», кодировка выбиралась исходя из предпочтений автора документа. По этой причине нередко, чтобы прочитать один документ, нужно было использовать разные таблицы. Иногда это приходилось делать по несколько раз, что существенно усложняло жизнь обычному пользователю. Как уже было сказано, решение этой проблемы в 1991 году было предложено некоммерческой организацией Unicode Inc., предложившей новый тип кодирования символов. Он был призван объединить морально устаревшие и разнообразные стандарты. «Юникод» — кодировка, которая озволила добиться немыслимого на тот момент: создать инструмент, поддерживающий огромное количество символов. Результат превзошел многие ожидания – появились документы, одновременно содержащие как английский, так и русский текст, латынь и математические выражения.

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

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

Небольшой исторический экскурс

Представьте, что на дворе 80-е. Компьютерная техника еще не так распространена и имеет вид, отличный от сегодняшнего. В то время каждая ОС по-своему уникальна и доработана каждым энтузиастом под конкретные нужды. Необходимость обмена информацией превращается в дополнительную доработку всего на свете. Попытка прочитать документ, созданный под другой ОС, зачастую выводит на экран непонятный набор символов, и начинаются игры с кодировкой. Не всегда получается сделать это быстро, и порой необходимый документ удаётся открыть через полгода, а то и позже. Люди, которые часто обмениваются информацией, создают для себя таблицы преобразования. И вот работа над ними выявляет интересную деталь: создавать их нужно по двум направлениям: «из моей в твою» и обратно. Сделать банальную инверсию вычислений машина не может, для нее в правом столбце исходник, а в левом — результат, но никак не наоборот. Если появлялась необходимость использовать какие-либо специальные символы в документе, их необходимо было сначала добавить, а потом еще и объяснить партнеру, что ему нужно сделать, чтобы эти символы не превратились в «кракозябры». И не будем забывать, что под каждую кодировку приходилось разрабатывать или внедрять собственные шрифты, что приводило к созданию огромного количества дублей в ОС.

Представьте еще, что на странице шрифтов вы увидите 10 штук идентичных Times New Roman с маленькими пометками: для UTF-8, UTF-16, ANSI, UCS-2. Теперь вы понимаете, что разработка универсального стандарта была настоятельной необходимостью?

кодировка Юникод

«Отцы-создатели»

Истоки создания Unicode следует искать в 1987 году, когда Джо Беккер из Xerox вместе с Ли Коллинзом и Марком Дэвисом из компании Apple начали исследования в сфере практического создания универсального набора символов. В августе 1988 года Джо Беккер опубликовал проект предложения по созданию 16-битной международной многоязычной системы кодирования.

Через несколько месяцев рабочая группа Unicode была расширена за счет включения Кена Уистлера и Майка Кернегана из RLG, Гленн Райт из Sun Microsystems и нескольких других специалистов, что позволило завершить работы по предварительному формированию единого стандарта кодирования.

юникод кодировка

Общее описание

В основе Unicode лежит понятие символа. Под этим определением понимается абстрактное явление, существующее в конкретном виде письменности и реализуемое через графемы (свои «портреты»). Каждый символ задается в «Юникоде» уникальным кодом, принадлежащим конкретному блоку стандарта. Например, графема B есть и в английском, и в русском алфавитах, но в Unicode ей соответствуют 2 разных символа. К ним применяется преобразование в строчную букву, т. е. каждый из них описывается ключом базы данных, набором свойств и полным названием.

Преимущества Unicode

От остальных современников кодировка «Юникод» отличалась огромным запасом знаков для «шифрования» символов. Дело в том, что его предшественники имели 8 бит, то есть поддерживали 28 символов, а вот новая разработка имела уже 216 символов, что стало гигантским шагом вперед. Это позволило закодировать практически все существующие и распространённые алфавиты.

С появлением «Юникода» отпала надобность использовать таблицы преобразования: как единый стандарт он просто сводил на нет их необходимость. Точно так же канули в Лету и «кракозябры» — единый стандарт сделал их невозможными, равно как и исключил необходимость создания дублей шрифтов.

Развитие Unicode

Конечно, прогресс не стоит на месте, и с момента первой презентации минуло уже 25 лет. Однако кодировка «Юникод» упрямо удерживает свои позиции в мире. Во многом это стало возможным благодаря тому, что он стал легко внедряемым и получил распространение, будучи признанным разработчикам проприетарного (платного) и открытого ПО.

кодировка юникод (стандарт кодирования символов)

При этом не стоит полагать, что сегодня нам доступна та же кодировка «Юникод», что и четверть века назад. На данный момент ее версия сменилась на 5.х.х, а количество кодируемых символов возросло до 231. От возможности использовать больший запас знаков отказались, чтобы всё еще сохранить поддержку для Unicode-16 (кодировки, где максимальное их количество ограничивалось цифрой 216). С момента своего появления и до версии 2.0.0 «Юникод-стандарт» увеличил количество символов, которые в него входили, практически в 2 раза. Рост возможностей продолжался и в последующие годы. К версии 4.0.0 уже появилась необходимость увеличить сам стандарт, что и было сделано. В результате «Юникод» обрел тот вид, в котором мы его знаем сегодня.

юникод что это такое

Что еще есть в Unicode?

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

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

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

юникод кодирование текстовой информации

Распространение стандарта

За 25 лет своей истории кодировка «Юникод» получила, вероятно, наибольшее распространение в мире. Под этот стандарт подгоняются также программы и web-страницы. О широте применения может говорить тот факт, что Unicode сегодня используют более 60 % интернет-ресурсов.

Теперь вам известно, когда появился стандарт «Юникод». Что это такое, вы также знаете и сможете оценить все значение изобретения, сделанного группой специалистов Unicode Inc. более 25 лет назад.

Про кодировки и Юникод / Habr

Вначале стоит разъяснить пару терминов. Кодовая страница — таблица заранее известного размера, каждой позиции (или коду) которой сопоставлен единственный символ или его отсутствие. Например, кодовая страница размерностью 256, где 71-й позиции соответствует буква «G». Кодировка — правило кодирования символа в числовое представление. Любая кодировка создается для определенной кодовой страницы. Для примера, символ «G» в кодировке Абрвал примет значение 71. Кстати, простейшие кодировки так и поступают — представляют символы их значениями в кодовых таблицах, ASCII тоже к таким относится.

Раньше для кодирования хватало всего 7 бит на символ. А что? достаточно для 128 различных знаков, вмещалось все необходимое тогдашним пользователям: английский алфавит, знаки препинания, цифры и некоторых спецсимволы. Основная англоязычная 7-битная кодировка с соответствующей ей кодовой страницей получили название ASCII (American Standard Code for Information Interchange), они же заложили основы на будущее. Позже, когда компьютеры распространились в неанглоговорящие страны, появилась нужда в национальных языках, здесь-то фундамент ASCII и пригодился. Компьютеры обрабатывают информацию на уровне байтов, а код ASCII занимает только 7 первых бит. Использование 8-го расширяло пространство до 256 мест без потери совместимости, а вместе с ней и поддержки английского языка, это было важно. На этом факте выстроено большинство неанглоязычных кодовых страниц и кодировок: нижние 128 позиций как у ASCII, а верхние 128 отведены для национальных нужд и кодировались со старшим битом. Однако, создание для каждого языка (иногда группы схожих языков) собственной страницы и кодировки привело к возникновению проблем с поддержкой такого хозяйства разработчиками операционных систем и программного обеспечения в целом.

Для выхода из ситуации организовали консорциум, разработавший и предложивший стандарт Юникода. В нем предполагалось объединить знаки всех языков мира в одной большой таблице. Кроме того, определялись кодировки. Сначала ребята посчитали, что 65 535 посадочных мест должно хватить всем, ввели UCS-2 — кодировку с фиксированной 16-битной длиной кодов. Но пришли азиаты с многотомными азбуками, и расчеты рухнули. Кодовую область увеличили вдвое, UCS-2 уже не смогла бы справиться, появилась 32-битная UCS-4. Ощутимыми преимуществами кодировок UCS являлись постоянная кратная двум длина кодов и простейший алгоритм кодирования, и то, и другое способствовало скорости обработки текса компьютером. Но при этом была и неоправданная, чересчур расточительная трата места: представьте, что в ASCII 00010101, то в UCS-2 00000000 00010101, а UCS-4 уже 00000000 00000000 00000000 00010101. С этим нужно было что-то делать.

Развитие Юникода повернуло в сторону кодировок с переменной длиной получаемых кодов. Представителями стали UTF-8, UTF-16 и UTF-32, последняя условно-досрочно, так как на данный момент она идентична UCS-4. Каждый символ в UTF-8 занимает от 8 до 32 бит, причем есть совместимость с ASCII. В UTF-16 16 или 32 бита, UTF-32 — 32 бита (если бы пространство Юникода расширили еще вдвое, то уже 32 или 64 бита), с ASCII эти две не дружат. Количество занимаемых байтов, зависит от позиции символа в таблице Юникода. Очевидно, наиболее практичная кодировка — UTF-8. Именно благодаря своей совместимости с ASCII, небольшой прожорливости до памяти и достаточно простым правилам кодирования, она является наиболее распространенной и перспективной кодировкой Юникода. Ну, а в завершение красивая схема преобразования кода символа в UTF-8:

Кодирование символов


 

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

Для кодировки символов в Windows используется таблица ASCII (American Standard Code for Interchange of Information).

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

СимволКодКлавишиЗначение
nul0Ctrl + @Нуль
soh1Ctrl + AНачало заголовка
stx2Ctrl + BНачало текста
etx3Ctrl + CКонец текста
eot4Ctrl + DКонец передачи
enq5Ctrl + EЗапрос
ack6Ctrl + FПодтверждение
bel7Ctrl + GСигнал (звонок)
bs8Ctrl + HЗабой (шаг назад)
ht9Ctrl + IГоризонтальная табуляция
lf10Ctrl + JПеревод строки
vt11Ctrl + KВертикальная табуляция
ff12Ctrl + LНовая страница
cr13Ctrl + MВозврат каретки
so14Ctrl + NВыключить сдвиг
si15Ctrl + OВключить сдвиг
dle16Ctrl + PКлюч связи данных
dc117Ctrl + QУправление устройством 1
dc218Ctrl + RУправление устройством 2
dc319Ctrl + SУправление устройством 3
dc420Ctrl + TУправление устройством 4
nak21Ctrl + UОтрицательное подтверждение
syn22Ctrl + VСинхронизация
etb23Ctrl + WКонец передаваемого блока
can24Ctrl + XОтказ
em25Ctrl + YКонец среды
sub26Ctrl + ZЗамена
esc27Ctrl + [Ключ
fs28Ctrl + \Разделитель файлов
gs29Ctrl + ]Разделитель группы
rs30Ctrl + ^Разделитель записей
us31Ctrl + _Разделитель модулей

Базовая таблица кодировки ASCII

32 пробел48 064 @80 P96 `112 p
33 !49 165 A81 Q97 a113 q
34 50 266 B82 R98 b114 r
35 #51 367 C83 S99 c115 s
36 $52 468 D84 T100 d116 t
37 %53 569 E85 U101 e117 u
38 &54 670 F86 V102 f118 v
39 ‘55 771 G87 W103 g119 w
40 (56 872 H88 X104 h120 x
41 )57 973 I89 Y105 i121 y
42 *58 :74 J90 Z106 j122 z
43 +59 ;75 K91 [107 k123 {
44 ,60 <76 L92 \108 l124 |
45 —61 =77 M93 ]109 m125 }
46 .62 >78 N94 ^110 n126 ~
47 /63 ?79 O95 _111 o127

Символы с номерами от 128 до 255 представляют собой таблицу расширения и варьируются в зависимости от набора скриптов, представленных кодировкой символов. Набор символов таблицы расширения различается в зависимости от выбранной кодовой страницы:

1251 – кодовая страница Windows

128 Ђ144 Ђ160176 °192 А208 Р224 а240 р
129 Ѓ145 ‘161 Ў177 ±193 Б209 С225 б241 с
130 ‚146 ’162 ў178 I194 В210 Т226 в242 т
131 ѓ147 “163 J179 i195 Г211 У227 г243 у
132 „148 ”164 ¤180 ґ196 Д212 Ф228 д244 ф
133 …149 •165 Ґ181 μ197 Е213 Х229 е245 х
134 †150 –166 ¦182 ¶198 Ж214 Ц230 ж246 ц
135 ‡151 —167 §183 ·199 З215 Ч231 з247 ч
136 €152 □168 Ё184 ё200 И216 Ш232 и248 ш
137 ‰153 ™169 ©185 №201 Й217 Щ233 й249 щ
138 Љ154 љ170 Є186 є202 К218 Ъ234 к250 ъ
139 <155 >171 «187 »203 Л219 Ы235 л251 ы
140 Њ156 њ172 ¬188 j204 М220 Ь236 м252 ь
141 Ќ157 ќ173189 S205 Н221 Э237 н253 э
142 Ћ158 ћ174 ®190 s206 О222 Ю238 о254 ю
143 Џ159 џ175 Ï191 ї207 П223 Я239 п255 я

866 – кодовая страница DOS

128 А144 Р160 а176 ░192 └208 ╨224 р240 ≡Ё
129 Б145 С161 б177 ▒193 ┴209 ╤225 с241 ±ё
130 В146 Т162 в178 ▓194 ┬210 ╥226 т242 ≥
131 Г147 У163 г179 │195 ├211 ╙227 у243 ≤
132 Д148 Ф164 д180 ┤196 ─212 ╘228 ф244 ⌠
133 Е149 Х165 е181 ╡197 ┼213 ╒229 х245 ⌡
134 Ж150 Ц166 ж182 ╢198 ╞214 ╓230 ц246 ¸
135 З151 Ч167 з183 ╖199 ╟215 ╫231 ч247 »
136 И152 Ш168 и184 ╕200 ╚216 ╪232 ш248 °
137 Й153 Щ169 й185 ╣201 ╔217 ┘233 щ249 ·
138 К154 Ъ170 к186 ║202 ╩218 ┌234 ъ250 ∙
139 Л155 Ы171 л187 ╗203 ╦219 █235 ы251 √
140 М156 Ь172 м188 ╝204 ╠220 ▄236 ь252 ⁿ
141 Н157 Э173 н189 ╜205 ═221 ▌237 э253 ²
142 О158 Ю174 о190 ╛206 ╬222 ▐238 ю254 ■
143 П159 Я175 п191 ┐207 ╧223 ▀239 я255

Русские названия основных спецсимволов:

СимволНазвание
`гравис, кавычка, обратный машинописный апостроф
`гравис, кавычка, обратный машинописный апостроф
~тильда
!восклицательный знак
@эт, коммерческое эт, «собака»
#октоторп, решетка, диез
$знак доллара
%процент
^циркумфлекс, знак вставки
&амперсанд
*астериск, звездочка, знак умножения
(левая открывающая круглая скобка
)правая закрывающая круглая скобка
минус, дефис
_знак подчеркивания
=знак равенства
+плюс
[левая открывающая квадратная скобка
]правая закрывающая квадратная скобка
{левая открывающая фигурная скобка
}правая закрывающая фигурная скобка
;точка с запятой
:двоеточие
машинописный апостроф, одинарная кавычка
«двойная кавычка
,запятая
.точка
/слэш, косая черта, знак дроби
<левая открытая угловая скобка, знак меньше
>правая закрытая угловая скобка, знак больше
\обратный слэш, обратная косая черта
|вертикальная черта

Кодировка UNICODE

Юникод (Unicode) — стандарт кодирования символов, позволяющий представить знаки практически всех письменных языков. Стандарт предложен в 1991 году некоммерческой организацией «Консорциум Юникода».

В Unicode используются 16-битовые (2-байтовые) коды, что позволяет представить 65536 символов.

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

Для представления символьных данных в кодировке Unicode используется символьный тип wchar_t.

ASCIIUNICODE
charwchar_t
1 байт2 байта

Тип кодировки задается в свойствах проекта Microsoft Visual Studio:
Кодировка Unicode
Кодировка Unicode
Многобайтовая кодировка предполагает использование кодировки ASCII.
При этом при построении проекта используется директива условной компиляции, переопределяющая тип TCHAR:

 
 
 
 
 

#ifdef _UNICODE
  typedef wchar_t TCHAR;
#else
  typedef char TCHAR;
#endif

Для перекодирования строки в формат Unicode без изменения кодировки файла используется макроопределение
_T(«строка»)

Прототип макроса содержится в файле tchar.h.


Назад: Представление данных и архитектура ЭВМ

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

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