Python. Преобразования

Русский профессор доктор наук В. Савельев утверждает, что у разных людей мозг может отличаться в разы. А если брать какие-то более узкие области мозга, то различия могут быть и до 40 раз.

С другой стороны все люди внешне выглядят примерно одинаково. Нет таких людей, физиологические данные (например, длина ног или размер ушей) которых отличались бы в 40 раз.

Другими словами, по внешним признакам сложно судить о человеке на сколько он умен. Собственно, поэтому и говорят: «Молчи, дурак, и за умного сойдёшь».

Ну я как бы дурак изначально, поэтому молчать мне особого смысла нет. А стало быть напишу-ка ещё одну статейку в свой бложек. На этот раз статья будет посвящена различным преобразованиям в Питоне.

Как-то так получилось, что я долгое время не мог осознать какие функции нужно применять для преобразования числа в символ и обратно — символа в число. Не-е, знать-то я знал, но как-то не особо понимал что вообще происходит. Зачем взятый из памяти компа байт нужно ещё как-то дополнительно преобразовывать в число для того чтобы произвести какие-то арифметические действия. В С/С++ такой фигни нет!

Допустим, мы получаем некоторый байт из последовательного порта и … И мы с ним не можем так просто работать. Его нужно сначала преобразовать в символ, если это символ. или в число, если это число. С непривычки крыша слегка сползает.

В С/С++ всё очень просто. Берёшь целочисленную переменную, размер которой один байт, и можешь ее интерпретировать как хочешь. Работаешь и не вздрагиваешь.

Вот бессмысленный (не имеющий какого-либо смысла) фрагмент кода на С/С++, который демонстрирует технику работы с данными.

uint8_t alpha, beta, gamma;

alpha = 65;
beta = 'A';

gamma = alpha + beta - 0x1E;  // gamma = 100;

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

Под символом понимается любая буква алфавита, цифра, любой печатный и непечатный (пробел, например) знак. Число — это просто число, с которым можно производить арифметические операции: складывать, вычитать, умножать, делить.

Проблему усугубляет еще и тот факт, что в Питоне как бы нет такой сущности как символ. Питон трактует символ как строку единичной длины. А символа, в понятиях С/С++, — в Питоне нет. Кроме того, символ не обязательно может занимать один байт в памяти компа, многое зависит от кодировки.

Я, например, работаю в Линуксе, и мой Питон использует кодировку utf-8. Что это значит? Это значит, что латиница, цифры и знаки препинания всегда кодируются одним байтом. А такие символы, как кириллица — двумя байтами. Иначе говоря, символ не имеет фиксированного (постоянного) размера: одни символы однобайтовые, другие — двубайтовые.

Строка символов, в которой кириллица используется вместе со знаками препинания или с цифрами выливается в сущую чехарду! Например, строка, в которой используется кириллица, имеет размер 10 символов. А в памяти эта строка будет занимать 14 байт. Ни рыба-ни мясо! Ни два, ни полтора.

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

Конечно, эти вопросы решаются. Но как! Это ж какие-то костыли и сплошные преобразования из одного формата в другой!

Следует заметить, что таких проблем при использовании только латиницы — нет и в помине! Америкосам нет никакой нужды для использования кириллицы или арабицы (или как оно там называется?). Они свой мир для себя сделали. А остальное — это исключительно наши проблемы.

Свои проблемы мы всегда сами решали. Во всяком случае так было 30 лет назад. Худо-бедно, но мы решали сами. А потом пошло и поехало! Мы перестали себя уважать и начали молиться на западные технологии. Дураки!

Прошедшее десятилетие ещё раз подтвердило, что мы сильно себя недооцениваем. Запад для нас как свет в окошке! Всё отечественное презираем и отвергаем не прикасаясь.

Слава богу, в последнее время тенденция начала меняться. Это радует. А то ведь жили по принципу: «Не читал, но осуждаю!» (с)

Ну, вот и доигрались! Америкосы устроили нам «похохотать». Их не интересуют проблемы аборигенов. Свои-то задачи они решили! Зачем они это нам подкинули? У меня есть большие подозрения — заставить нас бегать по дальнему кругу, огородами. Зачем? А затем, чтобы тратили силы на борьбу с «ветряными мельницами», а не занимались прогрессивными технологиями. Война — она ведь не только такая, где всё взрывается и льётся кровь. Война бывает экономическая, информационная… всякая. Не важно как ты это делаешь, важно что «партнёра» ты гасишь. Не даёшь ему вырваться вперёд.

Кодировка ASCII — что это? Это первые 127 кодов, к которым жестко привязаны символы латиницы. Причем этя привязка неизменна во всех других без исключения кодировках — в КОИ-8, в CP866, в CP1251, в UTF-8 и так далее… Я здесь перечислил далеко неполный список кодировок, использующих только кириллицу. А ведь в мире полно других кодировок. И во всех этих кодировках неизменна только кодировка латиницы. Вы понимаете? — У всех, кто использует коды символов выше 128, — у всех без исключения проблемы. И только у Америки на небе светит солнышко и поют птички.

А хочу обратить ваше внимание на тот факт, что как вам глубоко плевать на национальную кодировку какой-нибудь Норвегии или Латвии, так и американцам точно так же плевать на кодировки других алфавитов. Свою-то проблему они решили, а остальные — как хотят! Вы понимаете в чём заключается преимущество того, у кого в руках технологии?

Я ещё раз вернусь к мысли. Мы бы и сами решили свою проблему кодировки кириллицы, но хитрые америкосы услужливо завели нас в тупик. Мы ведь и раньше более-менее успешно решали проблемы кодировок. Решали эту проблему на компах до эпохи IBM PC. Решали эту проблему и в эпоху DOS. В эпоху Виндовса мы зачем ещё раз сменили кодировку. Какой в этом был сакральный смысл — остается только догадываться. Что означает «бнопня!», думаю, не все ещё забыли.

Всё это было ещё терпимо. И вот настала эпоха всеобщей интернатизации всего и вся. И снова все страны, за исключением США переделывают свои кодировки…

Я расцениваю это как замаскированную диверсию со стороны наших «партнёров». Лохи не должны догадываться, что они лохи! Это я про нас, если кто не понял.

Ну, хорошо, сегодня доминирует UTF-8. Давайте уже смиримся и успокоимся с этим балаганом.

Однако, а что нас ожидает завтра? Где гарантии того, что завтра мир не придумает какую-нибудь новую технологию, и история снова не повториться? Нет такой гарантии, ибо мы не самостоятельны, мы всё ещё плетёмся в хвосте и всё ещё зависимы от США. Я уверен, что при очередной смене технологии мы и все страны в очередной раз встанут раком, а США опять выйдут сухими и в белом смокинге. Диверсия? — Однозначно!

Однако, я уехал слишком сильно в сторону. Давайте возвращаться к теме статьи.

Я хочу привести граф, на котором показаны сущности (строка, число, символ) и функции, которые преобразуют одну сущность в другую.

python-converter

Немного поясню рисунок. Допустим, у нас есть число 65. Это десятичное число. Тогда функция chr(65) вернёт символ (строку из одного символа) — ‘A’. Мы можем обратно из символа ‘A’ получить число. Это делается с помощью функции ord().

Вот фрагмент код программы на Питоне:

alpha = 'A'
beta = ord(alpha)  # beta = 65
beta += 1
gamma = chr(beta)  # gamma = 'B'

print(alpha, beta, gamma)

Здесь символы ‘A’ и ‘B’ — это латинские буквы. Если вы используете Python3, то можно поиграться и с кириллицей. При использовании Python второй версии будет не всё так гладко.

alpha = 'Ж'
beta = ord(alpha)  # beta = 1046
beta -= 3
gamma = chr(beta)  # gamma = 'Г'

print(alpha, beta, gamma)

Заметьте, что размер символа уже в один байт не укладывается.

Теперь разберёмся со строками. Само по себе число в памяти компьютер никак не выглядит, оно не имеет внутреннего представления. Это абстракция. Внешнее представление абстракции может быть интерпретировано в виде символа, уровня напряжения, цвета или некоторого числа. Абстракция внутри компа никак не представлена. Абстракция — это просто набор битов, объединённых в байт, в полуслово, в слово, в двойное слово и так далее.

Ещё раз. Другими словами.

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

Как получить представление абстракции в виде символа мы уже знаем — с помощью функции chr(). А вот для представления абстракции в виде числа в Питоне существуют аж четыре функции:

  • bin() — для представления абстракции в виде двоичного числа
  • oct() — для представления абстракции в виде восьмеричного числа
  • str() — для представления абстракции в виде десятичного числа
  • hex() — для представления абстракции в виде шестнадцатеричного числа
beta = 1046     # Какая-то абстракция в памяти компа

d1 = bin(beta)  # d1 = '0b10000010110'
d2 = oct(beta)  # d2 = '0o2026'
d3 = str(beta)  # d3 = '1046'
d4 = hex(beta)  # d4 = '0x416'

print(beta, d1, d2, d3, d4)

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

123 и "123"

Первая сущность — это число, с которым можно выполнять арифметические действия. А вторая сущность — строка символов.

При сложении

123 + 123

мы получим новое значение, равное 246. Это число.

А при выполнении действия (при конкатенации)

"123" + "123"

мы тоже получим получим новое значение — «123123». Это новая строка символов.

Разница между С/С++ и Питоном состоит в том, что для С/С++ любое значение в памяти — это есть число. А вот для работы Питона требуется указать, как ему следует интерпретировать тот или иной байт в памяти. Поэтому такой фокус как

alpha = 'A' + 33

в Питоне не проходит. Для Питона лексема ‘A’ — это строка. К строке нельзя конкатенировать символьно и нельзя прибавить арифметически число 33.

В зависимости от наших намерений мы должны сделать либо так

alpha = ord('A') + 33  # alpha = 98 (число)

либо так

alpha = 'A' + chr(33)  # alpha = "A!" (строка)

Обратное преобразование — из строки символов в число. выполняет единственная функция int(). Она работает для всех четырёх форматов представления — для двоичного, восьмеричного, десятичного, шестнадцатеричного. Формат числа указывается во втором параметре.

Например:

d1 = '0b10000010110'
d2 = '0o2026'
d3 = '1046'
d4 = '0x416'

n1 = int(d1, 2)
n2 = int(d2, 8)
n3 = int(d3, 10)
n4 = int(d4, 16)
n5 = int("1046", 10)
n6 = int("0x416", 16)

print(d1, d2, d3, d4)
print(n1, n2, n3, n4, n5, n6)

Все шесть функций дадут одинаковый результат.

Причем, префикс («0x», «0b» или «0o») указывать не обязательно. Тогда следующие три преобразования дадут разные значения:

s1 = "2017"  # Это не число. Это всего лишь строка символов, выглядящая как число

n1 = int(s1, 8)    # n1 = 1039 (число)
n2 = int(s1, 10)   # n2 = 2017 (число)
n3 = int(s1, 16)   # n3 = 8215 (число)

print(n1, n2, n3)

На приведённой в тексте картинке допущена одна ошибка. Там я указал две сущности: символ и строку символов. На самом деле в Питоне символа не существует. Существует только строка. В данном случае длина этой строки всего один символ. Но это точно такая же строка.

Поскольку функции chr, str, hex и другие возвращают строку:

n1 = 1046

s1 = chr(n1)   # s1 = "Ж"    (строка)
s2 = str(n1)   # s2 = "1046" (строка)

print(n1, s1, s2)

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

Маленькое замечание. Все операции я выполнял в Питоне третьей версии. На это следует обратить внимание при использовании символов кириллицы. Во втором Питоне с символами кириллицы не всё гладко. Работать — работает, но, опять же, — только с помощью костылей.

Реклама

3 responses to “Python. Преобразования

  1. И ни слова про Unicode.

    • Ай! И без этого хватает сложности.

      Что касается Юникода, я так думаю, это временное решение.

      Мир соскочил с катушек. Ну, вот скажите мне, на кой хрен нужно вводить например символ «серп с молотом» в алфавит (в кодовую таблицу)? А православный крест, который устанавливают на могилах — его-то на кой хрен забубенили? А эмодзи?

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

      Есть и другая проблема. Я о ней уже упоминал — символы не имеют фиксированного размера. Ну сделайте все-все символы двубайтовыми. В том числе и первые 127 байт ASCII.

      Нельзя этого сделать! Рухнет латиница. Нельзя будет пользоваться ASCII. Америкосы огребут точно такие же проблемы, которые они нам создали.

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

      Есть же коды управления (\t, \a, \n и так далее). Давайте выделим код, который будет переключать кодировку. Что в этом сложного?

      У нас есть такой код как «вертикальная табуляция». Я не думаю, что он интенсивно используется в строковых коммуникациях. Ну или давайте задействуем тот же Esc (0x1B). В чём проблема-то?

      При выводе на экран или на печать строки символов тупо «шлепаем» латиницей, пока не встретится esc-символ. Этот символ не печатный, поэтому не печатаем его. Точно так же не печатаем как и символ звонка (0x07). Проблемы-то нет!

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

      Какие проблемы? Все терминалы работают на принципе esc-последовательностей! Накоплен громадный опыт. Программы существуют.

      Нет! Надо было изобрести очередной самокат с восмигранными колёсами. Кто-нибудь несёт ответственность за такие решения?

      Дай бог, чтобы в мире устаканился Юникод. Дай бог, чтобы UTF-8 окончательно вытеснила все остальные типы кодировки. Задрало ведь уже!

      Но ведь не такое гарантии! Вот в чём проблема.

      А как насчет кодировки символьных LCD-эранчиков? Там знаете какая кодировка (если они вообще имеют кириллицу!) установлена? — Крышу ведь рвёт не по детски!

      И только области американских букв — всё зашибись! Ну спасибо, «партнёры»! Молодцы, чо. Хороший ход. Всем странам жопу надрали, и сами в дамки прошли. Молодцы! И вроде как не специально это сотворили. Типа само так случилося. — Ага. Верим!

      И вот тут у меня очень большие сомнения, что на этом всё закончится. Очень, очень сложно подвести под общий знаменатель и писмо слева-направо, и справа-налево, и вертикальное сверху-вниз. Учесть обычные символы и символы-умляуты с диакритическими знаками. И иероглифы. А в каком-то алфавите даже цвет иимеет знаечние — это-то как учитывать!? А как насчет сортировки по алфавиту? А если требуется упорядочить строки с двумя национальными алфавитами, которые не относятся к латинице — например армянский и казахский?

      Вот, поэтому, я уверен, что колбасить мир будет ещё очень долго.

  2. Так это! Надо последовательно спускаться с горы…

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

    В википедии про юникод нормально написано, проблемы показаны, часть проблем сброшена на софт. Думать надо! Но перспективы однозначно есть!

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

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s