Skip to content

Instantly share code, notes, and snippets.

@w495
Last active March 26, 2018 01:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save w495/f4665140dc545d9dcc9429e11b486795 to your computer and use it in GitHub Desktop.
Save w495/f4665140dc545d9dcc9429e11b486795 to your computer and use it in GitHub Desktop.
Почему «Билл Гейтс» превратился в `«Р‘илл Гейтс»` или проблема с кодировками cp1251 и utf8
## РОДНОЕ ПРЕДСТАВЛЕНИЕ UTF8-СТРОКИ:
>>> [ord(i) for i in 'Бил Гейтс']
[208, 145, 208, 184, 208, 187,
32,
208, 147, 208, 181, 208, 185, 209, 130, 209, 129]
# Что тут происходит:
# * Я перебираю все символы строки через цикл FOR.
# * Вычисляю положение каждого символа
# в таблице ASCII через функцию `ord` (от слова `order`).
# * Обрати внимание:
# * все числа от 0 до 256.
# * число символов и чисел не совпадает:
# * каждый символ кириллицы представлен двумя числами;
# * 208 и 209 — префиксы характерные для кириллицы.
# * 32 — это пробел. Он представлен одним числом.
# Т.к. пробел и в Африке пробел.
# ПРЕДСТАВЛЕНИЕ UTF8-СТРОКИ В UNICODE
>>> [ord(i) for i in unicode('Бил Гейтс', 'utf8')]
[1041, 1080, 1083,
32,
1043, 1077, 1081, 1090, 1089]
# Что тут происходит:
# * Тоже самое, что и ранее.
# * Только предварительно привожу строку к Unicode.
# * Обрати внимание: Есть числа больше чем 256,
# зато число символов и чисел совпадает.
# * 32 — это пробел.
# Важный момент — минимальная единица представления информации — байты.
# В Unicode строки представлены списками чисел, а не байт.
# Потому на современной технике нет способа вывести на экран Unicode-строку.
# Её придется преобразовать во одно из байтовых представлений.
# Само по себе преобразование к UTF-8 — не простая задача.
# Наибоее примитивные пример выглядит так:
# https://github.com/w495/mai-workshops-2013/blob/ce9993c943f8a83d5cac9cd3b93c8bd589ae80f0/ws21/fls/fls.py#L246
# UTF-8 — это общепринятое представление Unicode строк в Интернете.
# Многие ОС, (Linux, Unix, Mac OS и пр.) стали использовать Unicode + UTF-8.
# Потому там нет проблем отображения. И в самой OC и в Интернете одна
# и та же кодировка. Однако, в некоторых случаях проблемы
# с кодировками остаются актуальными.
# Например, не понятно, как считать длину строки в UTF8.
# Для правильного вычисления постоянно приходится переводить в Unicode.
>>> len('Бил Гейтс') # Длина строки в UTF-8
17
>>> len(unicode('Бил Гейтс', 'utf8')) # Длина строки в Unicode
9
# На данный момент предлагается спрятать эту проблему на уровень ОС и
# интерпретаторов языков программирования, чтобы даже программисты
# об этом не задумывались. Но чудо — до сих пор не произошло.
# На дворе 2018. Но с 1985 почти ничего не изменилось.
# ПРЕДСТАВЛЕНИЕ ЭТО CP1251-СТРОКИ В UNICODE
>>> [ord(i) for i in unicode('Бил Гейтс', 'cp1251')]
[1056, 8216, 1056, 1105, 1056, 187,
32,
1056, 8220, 1056, 181, 1056, 8470, 1057, 8218, 1057, 1027]
# Что тут происходит:
# * Тоже самое, что и ранее.
# * Только к Unicode приводится строка из cp1251.
# * Из-за ошибочной интерпретации однобайтовая кодировка (cp1251)
# начинает восприниматься как многобайтовая.
# Потому каждому символу ставится в соответствие 2 числа.
# * 32 — это пробел.
# ПРЕДСТАВЛЕНИЕ ЭТО CP1251-СТРОКИ В UTF8
>>> [ord(i) for i in unicode('Бил Гейтс', 'cp1251').encode('utf8')]
[208, 160, 226, 128, 152, 208, 160, 209, 145, 208, 160, 194, 187,
32,
208, 160, 226, 128, 156, 208, 160, 194, 181, 208, 160, 226, 132,
150, 208, 161, 226, 128, 154, 208, 161, 208, 131]
# Что тут происходит:
# * Тоже самое, что и ранее.
# * Все числа большие 256 разбиваются на 2 числа меньшие 256.
# * 32 — это пробел.
# * При попыте вывести это на экран получаем «Р‘РёР» Гейтс»
@w495
Copy link
Author

w495 commented Mar 25, 2018

Навеяно картинкой:
Билл Гейтс и Стив Джобс, 1985 год

И ещё одной:
Почему «Билл Гейтс» превратился ⠫Билл Гейтс»

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment