Определить объем памяти, который потребуется для кодирования фразы Я помню чудесный момент в юникоде

Обновлено: 29.06.2024

В этом HOWTO обсуждается поддержка Unicode в Python и объясняются различные проблемы, с которыми обычно сталкиваются люди при попытке работать с Unicode.

Введение в Юникод¶

История кодов символов¶

В 1968 году был стандартизирован Американский стандартный код для обмена информацией, более известный под аббревиатурой ASCII. В ASCII определены числовые коды для различных символов с числовыми значениями от 0 до 127. Например, строчной букве «а» в качестве кодового значения присваивается 97.

ASCII — это стандарт, разработанный в США, поэтому он определяет только символы без диакритических знаков. Была буква «е», но не было ни «е», ни «и». Это означало, что языки, требующие символов с диакритическими знаками, не могли быть точно представлены в ASCII. (На самом деле отсутствующие акценты имеют значение и для английского языка, который содержит такие слова, как «naïve» и «café», а в некоторых публикациях есть собственный стиль, требующий написания, такого как «coöperate».)

Некоторое время люди просто писали программы, в которых не отображались диакритические знаки. Я помню, как смотрел программы Apple ][ BASIC, опубликованные во франкоязычных изданиях в середине 1980-х годов, в которых были такие строки:

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

Вы можете писать файлы, используя разные коды (все ваши русские файлы в системе кодирования под названием KOI8, все ваши французские файлы в другой системе кодирования под названием Latin1), но что, если вы хотите написать документ на французском языке, который цитирует какой-либо русский текст? ? В 1980-х люди захотели решить эту проблему, и начались усилия по стандартизации Unicode.

Есть родственный стандарт ISO, ISO 10646. Unicode и ISO 10646 изначально были отдельными проектами, но спецификации были объединены с версией 1.1 Unicode.

(Это обсуждение истории Unicode очень упрощено. Я не думаю, что среднестатистическому программисту Python нужно беспокоиться об исторических подробностях; за дополнительной информацией обращайтесь на сайт консорциума Unicode, указанный в Справочнике.)

Определения¶

Символ — это наименьший возможный компонент текста. «А», «В», «С» и т. д. — все это разные символы. Так же как и «Е» и «И». Персонажи — это абстракции, и они различаются в зависимости от языка или контекста, о котором вы говорите. Например, символ омов (Ω) обычно рисуется так же, как заглавная буква омега (Ω) в греческом алфавите (в некоторых шрифтах они могут быть даже одинаковыми), но это два разных символа, которые имеют разные значения. /p>

Стандарт Unicode описывает, как символы представляются кодовыми точками. Кодовая точка представляет собой целочисленное значение, обычно обозначаемое по основанию 16. В стандарте кодовая точка записывается с использованием обозначения U+12ca для обозначения символа со значением 0x12ca (десятичное число 4810). Стандарт Unicode содержит множество таблиц, в которых перечислены символы и соответствующие им кодовые точки:

Строго говоря, эти определения подразумевают, что бессмысленно говорить «это символ U+12ca». U+12ca — кодовая точка, обозначающая определенный символ; в данном случае он представляет символ «ЭФИОПСКИЙ СЛОГ WI». В неформальном контексте об этом различии между кодовыми точками и символами иногда забывают.

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

Кодировки¶

Подводя итог предыдущему разделу: строка Unicode представляет собой последовательность кодовых точек, то есть чисел от 0 до 0x10ffff. Эта последовательность должна быть представлена ​​в виде набора байтов (значения от 0 до 255) в памяти. Правила преобразования строки Unicode в последовательность байтов называются кодировкой.

Первая кодировка, о которой вы можете подумать, — это массив 32-битных целых чисел. В этом представлении строка «Python» будет выглядеть так:

Это представление простое, но его использование сопряжено с рядом проблем.

  1. Он не переносимый; разные процессоры упорядочивают байты по-разному.
  2. Это очень расточительно. В большинстве текстов большинство кодовых точек меньше 127 или меньше 255, поэтому много места занимают нулевые байты. Приведенная выше строка занимает 24 байта по сравнению с 6 байтами, необходимыми для представления ASCII. Увеличение использования ОЗУ не имеет большого значения (настольные компьютеры имеют мегабайты ОЗУ, а строки обычно не такие большие), но увеличение использования дисковой и сетевой пропускной способности в 4 раза недопустимо.
  3. Он не совместим с существующими функциями C, такими как strlen() , поэтому необходимо использовать новое семейство функций для работы с широкими строками.
  4. Многие интернет-стандарты определяются в терминах текстовых данных и не могут обрабатывать контент со встроенными нулевыми байтами.

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

Кодировки не должны обрабатывать все возможные символы Юникода, и большинство кодировок этого не делают. Например, кодировка Python по умолчанию — это кодировка «ascii». Правила преобразования строки Unicode в кодировку ASCII просты; для каждой кодовой точки:

Latin-1, также известная как ISO-8859-1, представляет собой аналогичную кодировку. Кодовые точки Unicode 0–255 идентичны значениям Latin-1, поэтому преобразование в эту кодировку просто требует преобразования кодовых точек в байтовые значения; если встречается кодовая точка больше 255, строка не может быть закодирована в Latin-1.

Кодировки не обязательно должны быть простыми однозначными сопоставлениями, такими как Latin-1. Рассмотрим EBCDIC от IBM, который использовался на мейнфреймах IBM. Буквенные значения не находились в одном блоке: от «a» до «i» имели значения от 129 до 137, а от «j» до «r» — от 145 до 153. Если вы хотите использовать EBCDIC в качестве кодировки, вы, вероятно, использовать какую-то таблицу поиска для выполнения преобразования, но это в основном внутренняя деталь.

  1. Если кодовая точка
  2. Если кодовая точка находится в диапазоне от 128 до 0x7ff, она преобразуется в двухбайтовые значения в диапазоне от 128 до 255.
  3. Кодовые точки >0x7ff преобразуются в трех- или четырехбайтовые последовательности, где каждый байт последовательности находится в диапазоне от 128 до 255.

UTF-8 имеет несколько удобных свойств:

Ссылки¶

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

Чтобы помочь понять стандарт, Юкка Корпела написал вводное руководство по чтению таблиц символов Unicode, доступное по адресу .

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

Записи в Википедии часто бывают полезны; см., например, записи для «кодировки символов» и UTF-8 .

Поддержка Unicode в Python¶

Теперь, когда вы изучили основы Unicode, мы можем рассмотреть возможности Unicode в Python.

Тип Unicode¶

Строки Unicode выражаются как экземпляры типа unicode, одного из встроенных типов Python. Он происходит от абстрактного типа с именем basestring, который также является предком типа str; поэтому вы можете проверить, является ли значение строковым типом, с помощью isinstance(value, basestring) . Под капотом Python представляет строки Unicode как 16- или 32-битные целые числа, в зависимости от того, как был скомпилирован интерпретатор Python.

Аргумент errors определяет реакцию, когда входная строка не может быть преобразована в соответствии с правилами кодирования. Допустимые значения для этого аргумента: «строгий» (возбуждает исключение UnicodeDecodeError), «заменяется» (добавляется U+FFFD, «ЗАМЕНА СИМВОЛА») или «игнорирует» (просто не включает символ в строку). Результат Юникод). В следующих примерах показаны различия:

Кодировки указываются в виде строк, содержащих имя кодировки. Python 2.4 поставляется с примерно 100 различными кодировками; список см. в справочнике по библиотеке Python в разделе Стандартные кодировки. Некоторые кодировки имеют несколько имен; например, «latin-1», «iso_8859_1» и «8859» являются синонимами одной и той же кодировки.

Односимвольные строки Unicode также можно создавать с помощью встроенной функции unichr(), которая принимает целые числа и возвращает строку Unicode длины 1, содержащую соответствующую кодовую точку. Обратной операцией является встроенная функция ord(), которая принимает односимвольную строку Unicode и возвращает значение кодовой точки:

Поэтому большая часть кода Python, работающего со строками, будет работать со строками Unicode без каких-либо изменений в коде. (Код ввода и вывода нуждается в дальнейшем обновлении для Unicode; подробнее об этом позже.)

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

Наиболее часто используемой частью модуля codecs являются codecs.open(), которая будет обсуждаться в разделе о вводе и выводе.

Литералы Unicode в исходном коде Python¶

В исходном коде Python литералы Unicode записываются в виде строк с префиксом "u" или "U": u'abcdefghijk' . Конкретные кодовые точки могут быть записаны с помощью escape-последовательности \u, за которой следуют четыре шестнадцатеричных цифры, обозначающие кодовую точку. Управляющая последовательность \U аналогична, но предполагает 8 шестнадцатеричных цифр, а не 4.

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

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

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

Синтаксис вдохновлен нотацией Emacs для указания переменных, локальных для файла. Emacs поддерживает множество различных переменных, а Python поддерживает только «кодирование». Символы -*- указывают Emacs, что комментарий является особым; они не имеют значения для Python, но являются соглашением. Python ищет coding: name или coding=name в комментарии.

Если вы не включите такой комментарий, по умолчанию будет использоваться кодировка ASCII. Версии Python до 2.4 были евроцентричными и предполагали Latin-1 в качестве кодировки по умолчанию для строковых литералов; в Python 2.4 символы больше 127 все еще работают, но приводят к предупреждению. Например, в следующей программе нет объявления кодировки:

При запуске с Python 2.4 выводится следующее предупреждение:

Свойства Юникода¶

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

Следующая программа отображает некоторую информацию о нескольких символах и печатает числовое значение одного конкретного символа:

При запуске выводится:

Коды категорий — это аббревиатуры, описывающие характер персонажа. Они сгруппированы в категории, такие как «Буквы», «Числа», «Пунктуация» или «Символ», которые, в свою очередь, разбиты на подкатегории. Чтобы взять коды из приведенного выше вывода, 'Ll' означает "Буква, нижний регистр", 'No' означает "Число, другое", 'Mn'< /tt> означает «Отметить, без пробела», а 'So' означает «Символ, другой». См. список кодов категорий.

Ссылки¶

Документация для модуля unicodedata.

Документация для модуля codecs.

Марк-Андре Лембург выступил на выставке EuroPython 2002 с докладом "Python и Unicode". PDF-версия его слайдов доступна по адресу , и представляет собой отличный обзор дизайна функций Unicode в Python.

Чтение и запись данных Unicode¶

После того как вы написали код, работающий с данными Unicode, следующей проблемой является ввод/вывод. Как вы получаете строки Unicode в свою программу и как вы конвертируете Unicode в форму, пригодную для хранения или передачи?

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

Одной из проблем является многобайтовая природа кодировок; один символ Unicode может быть представлен несколькими байтами. Если вы хотите читать файл порциями произвольного размера (скажем, 1 КБ или 4 КБ), вам нужно написать код обработки ошибок, чтобы поймать случай, когда в конце файла считывается только часть байтов, кодирующих один символ Юникода. кусок. Одним из решений было бы прочитать весь файл в память, а затем выполнить декодирование, но это мешает вам работать с очень большими файлами; если вам нужно прочитать 2Gb файл, вам нужно 2Gb оперативной памяти. (Более того, поскольку хотя бы на мгновение вам потребуется иметь в памяти как закодированную строку, так и ее версию Unicode.)

Решением может быть использование низкоуровневого интерфейса декодирования для выявления случаев неполных последовательностей кодирования. Работа по реализации этого уже сделана за вас: модуль codecs включает версию функции open(), которая возвращает файлоподобный объект, предполагающий содержимое файла. находятся в указанной кодировке и принимают параметры Unicode для таких методов, как .read() и .write() .

Поэтому чтение Unicode из файла очень просто:

Также можно открывать файлы в режиме обновления, допуская как чтение, так и запись:

Символ Unicode U+FEFF используется в качестве метки порядка байтов (BOM) и часто записывается как первый символ файла, чтобы облегчить автоматическое определение порядка байтов в файле. Некоторые кодировки, такие как UTF-16, предполагают наличие спецификации в начале файла; при использовании такой кодировки спецификация будет автоматически записана как первый символ и будет автоматически удалена при чтении файла. Существуют варианты этих кодировок, такие как utf-16-le и utf-16-be для кодировок с прямым и обратным порядком байтов, которые определяют один конкретный порядок байтов и не пропускают спецификацию.

Имена файлов Unicode¶

Большинство широко используемых сегодня операционных систем поддерживают имена файлов, содержащие произвольные символы Unicode. Обычно это реализуется путем преобразования строки Unicode в некоторую кодировку, которая различается в зависимости от системы. Например, Mac OS X использует UTF-8, а Windows использует настраиваемую кодировку; в Windows Python использует имя «mbcs» для обозначения текущей настроенной кодировки. В системах Unix кодировка файловой системы будет только в том случае, если вы установили переменные среды LANG или LC_CTYPE; если нет, кодировка по умолчанию — ASCII.

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

Функции в модуле os, такие как os.stat(), также принимают имена файлов в кодировке Unicode.

выведет следующий результат:

Советы по написанию программ, поддерживающих Unicode¶

В этом разделе приведены некоторые рекомендации по написанию программного обеспечения, работающего с Unicode.

Самый важный совет:

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

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

При использовании данных, поступающих из веб-браузера или другого ненадежного источника, обычно используется проверка на наличие недопустимых символов в строке перед использованием строки в сгенерированной командной строке или ее сохранением в базе данных. Если вы делаете это, будьте осторожны, чтобы проверить строку, как только она будет в форме, которая будет использоваться или храниться; кодировки могут использоваться для маскировки символов. Это особенно верно, если входные данные также указывают кодировку; во многих кодировках не используются обычно проверяемые символы, но Python включает некоторые кодировки, такие как 'base64', которые изменяют каждый отдельный символ.

Например, предположим, что у вас есть система управления контентом, которая использует имя файла в формате Unicode, и вы хотите запретить пути с символом «/». Вы можете написать этот код:

Однако, если злоумышленник может указать кодировку 'base64', он может передать 'L2V0Yy9wYXNzd2Q=' , которая представляет собой закодированную по основанию 64 форму строки < tt>'/etc/passwd' , чтобы прочитать системный файл. Приведенный выше код ищет символы '/' в закодированной форме и пропускает опасный символ в результирующей декодированной форме.

Ссылки¶

Слайды в формате PDF для презентации Марка-Андре Лембурга «Написание приложений с поддержкой Unicode на Python» доступны по адресу и обсуждают вопросы кодировки символов, а также способы интернационализации и локализации приложения.

История изменений и благодарность¶

Благодарим следующих людей, которые заметили ошибки или предложили предложения по этой статье: Николас Бастин, Мариус Гедминас, Кент Джонсон, Кен Круглер, Марк-Андре Лембург, Мартин фон Лёвис, Чад Уитакр.

Версия 1.0: опубликована 5 августа 2005 г.

Версия 1.01: опубликована 7 августа 2005 г. Исправлены фактические ошибки и ошибки разметки; добавляет несколько ссылок.

В этом HOWTO обсуждается поддержка Unicode в Python 2.x и объясняются различные проблемы, с которыми обычно сталкиваются люди при попытке работать с Unicode. Версию для Python 3 см. в разделе .

Введение в Юникод¶

История кодов символов¶

В 1968 году был стандартизирован Американский стандартный код для обмена информацией, более известный под аббревиатурой ASCII. В ASCII определены числовые коды для различных символов с числовыми значениями от 0 до 127. Например, строчной букве «а» в качестве кодового значения присваивается 97.

ASCII — это стандарт, разработанный в США, поэтому он определяет только символы без диакритических знаков. Была буква «е», но не было ни «е», ни «и». Это означало, что языки, требующие символов с диакритическими знаками, не могли быть точно представлены в ASCII. (На самом деле отсутствующие акценты имеют значение и для английского языка, который содержит такие слова, как «naïve» и «café», а в некоторых публикациях есть собственный стиль, требующий написания, такого как «coöperate».)

Некоторое время люди просто писали программы, в которых не отображались диакритические знаки. Я помню, как смотрел программы Apple ][ BASIC, опубликованные во франкоязычных изданиях в середине 1980-х годов, в которых были такие строки:

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

Вы можете писать файлы, используя разные коды (все ваши русские файлы в системе кодирования под названием KOI8, все ваши французские файлы в другой системе кодирования под названием Latin1), но что, если вы хотите написать документ на французском языке, который цитирует какой-либо русский текст? ? В 1980-х люди захотели решить эту проблему, и начались усилия по стандартизации Unicode.

Есть родственный стандарт ISO, ISO 10646. Unicode и ISO 10646 изначально были отдельными проектами, но спецификации были объединены с версией 1.1 Unicode.

(Это обсуждение истории Unicode очень упрощено. Я не думаю, что среднестатистическому программисту Python нужно беспокоиться об исторических подробностях; за дополнительной информацией обращайтесь на сайт консорциума Unicode, указанный в Справочнике.)

Определения¶

Символ — это наименьший возможный компонент текста. «А», «В», «С» и т. д. — все это разные символы. Так же как и «Е» и «И». Персонажи — это абстракции, и они различаются в зависимости от языка или контекста, о котором вы говорите. Например, символ омов (Ω) обычно рисуется так же, как заглавная буква омега (Ω) в греческом алфавите (в некоторых шрифтах они могут быть даже одинаковыми), но это два разных символа, которые имеют разные значения. /p>

Стандарт Unicode описывает, как символы представляются кодовыми точками. Кодовая точка представляет собой целочисленное значение, обычно обозначаемое по основанию 16. В стандарте кодовая точка записывается с использованием обозначения U+12ca для обозначения символа со значением 0x12ca (десятичное число 4810). Стандарт Unicode содержит множество таблиц, в которых перечислены символы и соответствующие им кодовые точки:

Строго говоря, эти определения подразумевают, что бессмысленно говорить «это символ U+12ca». U+12ca — кодовая точка, обозначающая определенный символ; в данном случае он представляет символ «ЭФИОПСКИЙ СЛОГ WI». В неформальном контексте об этом различии между кодовыми точками и символами иногда забывают.

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

Кодировки¶

Подводя итог предыдущему разделу: строка Unicode представляет собой последовательность кодовых точек, то есть чисел от 0 до 0x10ffff. Эта последовательность должна быть представлена ​​в виде набора байтов (значения от 0 до 255) в памяти. Правила преобразования строки Unicode в последовательность байтов называются кодировкой.

Первая кодировка, о которой вы можете подумать, — это массив 32-битных целых чисел. В этом представлении строка «Python» будет выглядеть так:

Это представление простое, но его использование сопряжено с рядом проблем.

  1. Он не переносимый; разные процессоры упорядочивают байты по-разному.
  2. Это очень расточительно. В большинстве текстов большинство кодовых точек меньше 127 или меньше 255, поэтому много места занимают нулевые байты. Приведенная выше строка занимает 24 байта по сравнению с 6 байтами, необходимыми для представления ASCII. Увеличение использования ОЗУ не имеет большого значения (настольные компьютеры имеют мегабайты ОЗУ, а строки обычно не такие большие), но увеличение использования дисковой и сетевой пропускной способности в 4 раза недопустимо.
  3. Он не совместим с существующими функциями C, такими как strlen() , поэтому необходимо использовать новое семейство функций для работы с широкими строками.
  4. Многие интернет-стандарты определяются в терминах текстовых данных и не могут обрабатывать контент со встроенными нулевыми байтами.

Обычно люди не используют эту кодировку, вместо этого выбирая другие кодировки, более эффективные и удобные. UTF-8, вероятно, является наиболее часто поддерживаемой кодировкой; это будет обсуждаться ниже.

Кодировки не должны обрабатывать все возможные символы Юникода, и большинство кодировок этого не делают. Например, кодировка Python по умолчанию — это кодировка «ascii». Правила преобразования строки Unicode в кодировку ASCII просты; для каждой кодовой точки:

Latin-1, также известная как ISO-8859-1, представляет собой аналогичную кодировку. Кодовые точки Unicode 0–255 идентичны значениям Latin-1, поэтому преобразование в эту кодировку просто требует преобразования кодовых точек в байтовые значения; если встречается кодовая точка больше 255, строка не может быть закодирована в Latin-1.

Кодировки не обязательно должны быть простыми однозначными сопоставлениями, такими как Latin-1. Рассмотрим EBCDIC от IBM, который использовался на мейнфреймах IBM. Буквенные значения не находились в одном блоке: от «a» до «i» имели значения от 129 до 137, а от «j» до «r» — от 145 до 153. Если вы хотите использовать EBCDIC в качестве кодировки, вы, вероятно, использовать какую-то таблицу поиска для выполнения преобразования, но это в основном внутренняя деталь.

  1. Если кодовая точка
  2. Если кодовая точка находится в диапазоне от 128 до 0x7ff, она преобразуется в двухбайтовые значения в диапазоне от 128 до 255.
  3. Кодовые точки >0x7ff преобразуются в трех- или четырехбайтовые последовательности, где каждый байт последовательности находится в диапазоне от 128 до 255.

UTF-8 имеет несколько удобных свойств:

Ссылки¶

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

Чтобы помочь понять стандарт, Юкка Корпела написал вводное руководство по чтению таблиц символов Unicode, доступное по адресу .

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

Записи в Википедии часто бывают полезны; см., например, записи для «кодировки символов» и UTF-8 .

Поддержка Unicode в Python 2.x¶

Теперь, когда вы изучили основы Unicode, мы можем рассмотреть возможности Unicode в Python.

Тип Unicode¶

Строки Unicode выражаются как экземпляры типа unicode, одного из встроенных типов Python. Он происходит от абстрактного типа с именем basestring, который также является предком типа str; поэтому вы можете проверить, является ли значение строковым типом, с помощью isinstance(value, basestring) . Под капотом Python представляет строки Unicode как 16- или 32-битные целые числа, в зависимости от того, как был скомпилирован интерпретатор Python.

Аргумент errors определяет реакцию, когда входная строка не может быть преобразована в соответствии с правилами кодирования. Допустимые значения для этого аргумента: «строгий» (возбуждает исключение UnicodeDecodeError), «заменяется» (добавляется U+FFFD, «ЗАМЕНА СИМВОЛА») или «игнорирует» (просто не включает символ в строку). Результат Юникод). В следующих примерах показаны различия:

Кодировки указываются в виде строк, содержащих имя кодировки. Python 2.7 поставляется примерно со 100 различными кодировками; список см. в справочнике по библиотеке Python в разделе Стандартные кодировки. Некоторые кодировки имеют несколько имен; например, «latin-1», «iso_8859_1» и «8859» являются синонимами одной и той же кодировки.

Односимвольные строки Unicode также можно создавать с помощью встроенной функции unichr(), которая принимает целые числа и возвращает строку Unicode длины 1, содержащую соответствующую кодовую точку. Обратной операцией является встроенная функция ord(), которая принимает односимвольную строку Unicode и возвращает значение кодовой точки:

Поэтому большая часть кода Python, работающего со строками, будет работать со строками Unicode без каких-либо изменений в коде. (Код ввода и вывода нуждается в дальнейшем обновлении для Unicode; подробнее об этом позже.)

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

Наиболее часто используемой частью модуля codecs является функция codecs.open(), которая будет обсуждаться в разделе о вводе и выводе.

Литералы Unicode в исходном коде Python¶

В исходном коде Python литералы Unicode записываются в виде строк с префиксом "u" или "U": u'abcdefghijk' . Конкретные кодовые точки могут быть записаны с помощью escape-последовательности \u, за которой следуют четыре шестнадцатеричных цифры, обозначающие кодовую точку. Управляющая последовательность \U аналогична, но предполагает 8 шестнадцатеричных цифр, а не 4.

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

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

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

Синтаксис вдохновлен нотацией Emacs для указания переменных, локальных для файла. Emacs поддерживает множество различных переменных, а Python поддерживает только «кодирование». Символы -*- указывают Emacs, что комментарий является особым; они не имеют значения для Python, но являются соглашением. Python ищет coding: name или coding=name в комментарии.

Если вы не включите такой комментарий, по умолчанию будет использоваться кодировка ASCII. Версии Python до 2.4 были евроцентричными и предполагали Latin-1 в качестве кодировки по умолчанию для строковых литералов; в Python 2.4 символы больше 127 все еще работают, но приводят к предупреждению. Например, в следующей программе нет объявления кодировки:

При запуске с Python 2.4 выводится следующее предупреждение:

Python 2.5 и более поздние версии являются более строгими и будут вызывать синтаксическую ошибку:

Свойства Юникода¶

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

Следующая программа отображает некоторую информацию о нескольких символах и печатает числовое значение одного конкретного символа:

При запуске выводится:

Коды категорий — это аббревиатуры, описывающие характер персонажа. Они сгруппированы в категории, такие как «Буквы», «Числа», «Пунктуация» или «Символ», которые, в свою очередь, разбиты на подкатегории. Чтобы взять коды из приведенного выше вывода, 'Ll' означает "Буква, нижний регистр", 'No' означает "Число, другое", 'Mn'< /tt> означает «Отметить, без пробела», а 'So' означает «Символ, другой». См. список кодов категорий.

Ссылки¶

Документация для модуля unicodedata.

Документация для модуля codecs.

Марк-Андре Лембург выступил на выставке EuroPython 2002 с докладом "Python и Unicode". PDF-версия его слайдов доступна по адресу , и представляет собой отличный обзор дизайна функций Unicode в Python.

Чтение и запись данных Unicode¶

После того как вы написали код, работающий с данными Unicode, следующей проблемой является ввод/вывод. Как вы получаете строки Unicode в свою программу и как вы конвертируете Unicode в форму, пригодную для хранения или передачи?

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

Одной из проблем является многобайтовая природа кодировок; один символ Unicode может быть представлен несколькими байтами. Если вы хотите читать файл порциями произвольного размера (скажем, 1 КБ или 4 КБ), вам нужно написать код обработки ошибок, чтобы поймать случай, когда в конце файла считывается только часть байтов, кодирующих один символ Юникода. кусок. Одним из решений было бы прочитать весь файл в память, а затем выполнить декодирование, но это мешает вам работать с очень большими файлами; если вам нужно прочитать 2Gb файл, вам нужно 2Gb оперативной памяти. (Более того, поскольку хотя бы на мгновение вам потребуется иметь в памяти как закодированную строку, так и ее версию Unicode.)

Решением может быть использование низкоуровневого интерфейса декодирования для выявления случаев неполных последовательностей кодирования.Работа по реализации этого уже сделана за вас: модуль codecs включает версию функции open(), которая возвращает файлоподобный объект, предполагающий содержимое файла. находятся в указанной кодировке и принимают параметры Unicode для таких методов, как .read() и .write() .

Поэтому чтение Unicode из файла очень просто:

Также можно открывать файлы в режиме обновления, допуская как чтение, так и запись:

Символ Unicode U+FEFF используется в качестве метки порядка байтов (BOM) и часто записывается как первый символ файла, чтобы облегчить автоматическое определение порядка байтов в файле. Некоторые кодировки, такие как UTF-16, предполагают наличие спецификации в начале файла; при использовании такой кодировки спецификация будет автоматически записана как первый символ и будет автоматически удалена при чтении файла. Существуют варианты этих кодировок, такие как utf-16-le и utf-16-be для кодировок с прямым и обратным порядком байтов, которые определяют один конкретный порядок байтов и не пропускают спецификацию.

Имена файлов Unicode¶

Большинство широко используемых сегодня операционных систем поддерживают имена файлов, содержащие произвольные символы Unicode. Обычно это реализуется путем преобразования строки Unicode в некоторую кодировку, которая различается в зависимости от системы. Например, Mac OS X использует UTF-8, а Windows использует настраиваемую кодировку; в Windows Python использует имя «mbcs» для обозначения текущей настроенной кодировки. В системах Unix кодировка файловой системы будет только в том случае, если вы установили переменные среды LANG или LC_CTYPE; если нет, кодировка по умолчанию — ASCII.

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

Функции в модуле os, такие как os.stat(), также принимают имена файлов в кодировке Unicode.

выведет следующий результат:

Советы по написанию программ, поддерживающих Unicode¶

В этом разделе приведены некоторые рекомендации по написанию программного обеспечения, работающего с Unicode.

Самый важный совет:

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

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

При использовании данных, поступающих из веб-браузера или другого ненадежного источника, обычно используется проверка на наличие недопустимых символов в строке перед использованием строки в сгенерированной командной строке или ее сохранением в базе данных. Если вы делаете это, будьте осторожны, чтобы проверить строку, как только она будет в форме, которая будет использоваться или храниться; кодировки могут использоваться для маскировки символов. Это особенно верно, если входные данные также указывают кодировку; во многих кодировках не используются обычно проверяемые символы, но Python включает некоторые кодировки, такие как 'base64', которые изменяют каждый отдельный символ.

Например, предположим, что у вас есть система управления контентом, которая использует имя файла в формате Unicode, и вы хотите запретить пути с символом «/». Вы можете написать этот код:

Однако, если злоумышленник может указать кодировку 'base64', он может передать 'L2V0Yy9wYXNzd2Q=' , которая представляет собой закодированную по основанию 64 форму строки < tt>'/etc/passwd' , чтобы прочитать системный файл. Приведенный выше код ищет символы '/' в закодированной форме и пропускает опасный символ в результирующей декодированной форме.

Ссылки¶

Слайды в формате PDF для презентации Марка-Андре Лембурга «Написание приложений с поддержкой Unicode на Python» доступны по адресу и обсуждают вопросы кодировки символов, а также способы интернационализации и локализации приложения.

История изменений и благодарность¶

Благодарим следующих людей, которые заметили ошибки или предложили предложения по этой статье: Николас Бастин, Мариус Гедминас, Кент Джонсон, Кен Круглер, Марк-Андре Лембург, Мартин фон Лёвис, Чад Уитакр.

Версия 1.0: опубликована 5 августа 2005 г.

Версия 1.01: опубликована 7 августа 2005 г. Исправлены фактические ошибки и ошибки разметки; добавляет несколько ссылок.

Версия 1.02: опубликована 16 августа 2005 г. Исправлены фактические ошибки.

Версия 1.03: опубликована 20 июня 2010 г. Обратите внимание, что Python 3.x не рассматривается, а HOWTO охватывает только 2.x.

Раздел 404 Закона Сарбейнса-Оксли (SOX) требует, чтобы все публичные компании установили внутренний контроль и процедуры.

Закон о защите конфиденциальности детей в Интернете от 1998 года (COPPA) – это федеральный закон, который налагает особые требования на операторов доменов .

План North American Electric Reliability Corporation по защите критически важной инфраструктуры (NERC CIP) представляет собой набор стандартов.

Стандарт безопасности данных платежных приложений (PA-DSS) – это набор требований, призванных помочь поставщикам программного обеспечения в разработке безопасных .

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

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

Медицинская транскрипция (МТ) – это ручная обработка голосовых сообщений, продиктованных врачами и другими медицинскими работниками.

Электронное отделение интенсивной терапии (eICU) — это форма или модель телемедицины, в которой используются самые современные технологии.

Защищенная медицинская информация (PHI), также называемая личной медицинской информацией, представляет собой демографическую информацию, медицинскую .

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

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

Синхронная репликация — это процесс копирования данных по сети хранения, локальной или глобальной сети, поэтому .

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

API облачного хранилища — это интерфейс прикладного программирования, который соединяет локальное приложение с облачным хранилищем.

Интерфейс управления облачными данными (CDMI) – это международный стандарт, определяющий функциональный интерфейс, используемый приложениями.


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

Когда нужно кодировать/декодировать("UTF-8")? Что именно он делает? Что такого особенного в unicode("abc") или он идентичен u"abc"?

Почему, если я использую HTML-кодировку UTF8, python-скрипт с кодировкой UTF-8 и оболочку с поддержкой UTF-8, и все они взаимодействуют друг с другом, я должен случайным образом начать добавлять вышеуказанные функции? пока вещи случайно не сломаются? :)

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


Факты из жизни

Все входные и выходные данные вашей программы — байты.

Для передачи текста миру требуется более 256 символов.

Ваша программа должна работать как с байтами, так и с Unicode.

Поток байтов не может определить его кодировку.

Параметры кодирования могут быть неправильными.

Советы

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

Проверьте поддержку Unicode. Используйте экзотические строки во всех своих наборах тестов, чтобы убедиться, что вы охватываете все случаи.

В python есть два типа строк: строки байтов и строки юникода. Каждый элемент в байтовой строке является байтом. Есть только 256 возможных байтов. Каждый элемент в строке Юникода является символом (также называемым кодовой точкой Юникода). В Юникоде определено чуть более миллиона символов. Это означает, что каждый элемент/символ в строке Unicode может быть одним из этих миллионов символов.

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

Вы кодируете его. кодировка – это представление строки Юникода. Он определяет байт или последовательность байтов для каждой* кодовой точки Unicode; по сути таблица перевода. Для каждой кодовой точки Юникода существует байт или последовательность байтов.

Есть еще кое-что, но это основные моменты, которые вам нужно знать. Когда вы пишете программу, это означает, что вы хотите манипулировать строками Unicode повсюду, и когда вы хотите вывести строку (в файл или по сети), вы кодируете ее. Когда вы читаете строку байтов из внешних источников, вы декодируете ее. Есть ли в этом смысл?

*некоторые кодировки могут не поддерживать все символы Юникода; они могут поддерживать только некоторое подмножество юникода. UTF-8 хорош тем, что поддерживает все. Он определяет последовательность байтов для каждого символа Юникода.

Для большей путаницы имена типов в Python 2 и 3 перемешаны.

str — это строка байтов

unicode – это строка в формате Unicode

bytes — это строка байтов

str – это строка в Юникоде

Причина в том, что строки Python 3 по умолчанию являются абстрактными строками Unicode (не закодированными в какой-либо конкретной кодировке). Закодированные строки (UTF-8, Latin1 и т. д.) считаются двоичными.

Хорошо, думаю, моя главная проблема заключалась в том, что я использовал синонимы Unicode и UTF-8. Простое понимание того, что делает определенная кодировка, очень поучительно.

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

Чтобы ответить на ваши конкретные вопросы:

когда вы кодируете ("UTF-8"), вы конвертируете строку Unicode в строку байтов. Его следует вызывать для строк Unicode.

При декодировании ("UTF-8") вы преобразуете строку байтов в строку Unicode. Его следует вызывать для байтовых строк.

unicode("abc") совпадает с u"abc": они оба создают строку Unicode из трех символов.

Большая часть путаницы возникает из-за того, что python 2 работает быстро и свободно со строками Unicode. Он будет пытаться преобразовать их для вас, когда вы смешиваете их вместе, что дает неожиданные результаты. Python 3 имеет гораздо более разумное поведение: он заставляет вас явно кодировать или декодировать для преобразования между ними.

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

Есть ли канонический исходный код comp sci для декодирования на краях? Я спорил с некоторыми пользователями Delphi об этом целую неделю. Никто из тех, кто использует Python, не считается источником, потому что все мы сценаристы, которые хотят, чтобы другие делали для нас вещи, которые нам слишком сложно понять.

<блочная цитата>

3. Даже если вы хотите притвориться, что не работаете с кодировкой, вы всегда это делаете. Если вы предпочитаете не понимать, что происходит с вашими строковыми кодировками, и думаете, что это имеет значение только «по краям», то вы либо: a. в блаженном неведении и не сможет справиться, если что-то пойдет не так, как ожидалось, или b. повезло, что вообще не приходилось сталкиваться с такими проблемами. Я ожидаю, что это b для вас. Для 99,999% моего кода мне все равно, как кодируются мои строки. Это не значит, что я могу притворяться, будто 0,001 % не нужны для решения.

Это наука. Вы декодируете UTF-8, когда читаете текст в кодировке UTF-8, например, с веб-страницы или текстового файла.

Это старое, но (IMO) очень хорошо изложенное объяснение кодировок символов и Unicode:

О боже. Я целую неделю спорил об этом с пользователями Delphi, которые сходят с ума по поводу того, что в следующей версии их языка больше не будет четырех(!) типов строк, которые есть сейчас, плюс три типа char.

Они сказали бы вам, что, возможно, вам нужно декодировать/кодировать только по краям, но для важной работы, которую они выполняют, и из соображений производительности им нужно делать иначе. И что вы, по-видимому, не понимаете Unicode так, как они, и вы, вероятно, ребенок-сценарист, и что вы на самом деле говорите, что вам не нужно это делать, так что никому не нужно действительно понимаю Юникод. :-( Бла, бла, бла, регулярные выражения, бла, бла, бла.

Я уже продемонстрировал вам, что это может негативно сказаться на производительности. Иногда вы можете себе это позволить, иногда нет. Конечно, это проще (особенно если кто-то позаботится об этом вместо вас), но может оказаться недостаточно производительным.

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

По возможности прекратите использование python2.

Для кодирования символа ∴ в кодировке utf-8 требуется 3 байта, и эти байты равны 0xe2 0x88 0xb4 . Это хорошо и хорошо — у вас есть допустимые байты utf-8 — но теперь вы нарушили модель итерации Python. Это трехбайтовая строка, но она должна представлять только один символ. Если бы вы перебирали эту строку, вы бы получили три символа, ни один из которых не был бы "∴"

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

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

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

Первый символ ∴ автоматически кодируется в utf-8. Второй ∴ закодирован мной в utf-7. Они идут вместе, как горох и аборт. Ни один разумный инструмент никогда не будет правильно декодировать это, и тип Unicode никогда не будет страдать от этой проблемы. Если вы можете приучить себя использовать только строки Unicode, тогда символы — это просто символы, и их закодированные байтовые представления не нужно обрабатывать, кроме как на границах, где данные покидают Python или данные входят в Python.

Изменить: для упрощения запомните это—

кодировать: превратить идеализированный магический юникод в байты

декодировать: превратить байты в идеализированный магический юникод

Edit2: для педантичных людей "идеализированный магический юникод" означает "кодовые точки юникода" или "тип юникода Python 2"

Когда вы помещаете не-ascii-символ в строковый литерал python2, python2 закодирует этот символ кодировкой по умолчанию (вероятно, utf-8).

Нет. Скорее: вы передаете символ в python в заданной кодировке (в unix, вероятно, utf-8, в windows это зависит от вашей локали) - т.е. в виде набора байтов. Вы можете сохранить эти байты в объекте str. Волшебство происходит, когда вы используете конструктор Unicode — u"∴" интерпретируется как "∴".decode(sys.defaultencoding).

Далее, '∴' + u'∴'.encode('utf-7') является совершенно законной конструкцией: она в основном такая же, как "∴" + "∴".decode(sys.defaultencoding).encode ('utf-7'), что совпадает с u"\u2234".encode(sys.defaultencoding) + u"\u2234".encode('utf-7').

Юникод в Python 3 практически такой же. Python 2 ведет себя несколько неудобно, но принципиально не хуже и не отличается в обработке текста/байтов.

Глядя с точки зрения Python 2.x, вы должны думать о строке в Python просто как о массиве бессмысленных байтов, а о юникоде – как о волшебном абстрактном типе, способном представляющий любой существующий символ (если он описан в стандарте Unicode). До изменений Unicode в Python бессмысленный массив байтов (ab) использовался как строковый тип. Это работало, потому что ASCII имеет достаточно небольшое количество символов, чтобы каждый символ мог быть представлен одним байтом. Добавление поддержки Unicode сделало обработку строк на первый взгляд более сложной, но также более правильной и, следовательно, менее подверженной ошибкам, поскольку исходный подход был хаком.

Конечно, сам тип Unicode также использует конкретное байтовое представление строки внутри, даже до того, как вы ее закодируете, но это скрытая деталь реализации, и она не имеет значения (если только вы не пытаетесь оценить использование памяти).< /p>

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

В Python 3.x прежний тип string был переименован в более подходящее имя bytes, а имя string теперь представляет прежний тип unicode.

История информатики — это история, когда пространство было сильно ограничено, и оно все еще существует на некоторых устройствах, таких как портативные устройства или небольшая электроника. В этих случаях нам нужен был и все еще нужен способ представления символов с использованием небольшого количества места или памяти.ASCII (американский стандартный код для обмена информацией) был одним из самых популярных способов сделать это. Он сопоставляет числа с символами, и в этом случае, при способе сопоставления ASCII, вы можете использовать только 7 бит или 7 цифр с 2 возможными значениями: 0 или 1 для представления всех этих символов. В большинстве случаев используется целый байт или 8 бит. Например, значение 110 0001 или 97 в десятичном формате соответствует символу «а» с использованием таблицы ASCII. Строка в ASCII — это просто список чисел, в котором каждое отдельное число соответствует символу. Например, строка «привет» сопоставляется со списком чисел [104, 101, 108, 108, 111].

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

В конце концов, учреждение решило создать первичную таблицу сопоставления, самую большую из когда-либо существовавших таблиц или таблицу для представления всех возможных символов из всех существующих, прошлых, возможно, будущих и даже вымерших языков. Их творение назвали Unicode. Символы Unicode отображаются с использованием большой таблицы, основанной на 32-битном представлении, что означает, что каждый символ имеет длину 4 байта или 32 бита. Например, тот же символ «а» по-прежнему имеет номер 97 в таблице сопоставления Unicode.

Python предлагает множество различных способов манипулирования и представления списка чисел, списка байтов, списка символов ASCII и списка символов Unicode. Когда вы вводите u'abc' в Python, вы указываете список символов Unicode. Когда вы вводите «abc» в Python 2, вы указываете список символов ASCII или, по сути, список байтов. Эти вещи немного отличаются в Python 3, но я подозреваю, что вы используете Python 2.

В Unicode есть несколько способов сопоставить список символов Unicode со списком байтов. Глупый способ - это UTF-32, который сопоставляет каждый символ Юникода с соответствующими 4 байтами. Если список символов Юникода, который у вас есть, в основном основан на английском или латинском языках, это хорошая причина использовать более разумный способ или способ, который будет занимать меньше места. UTF-8 - это такой способ. Он попытается использовать то же сопоставление, что и ASCII, для того же символа, который будет использовать 1 байт пространства для этого символа и будет использовать больше байтов для расширенных символов. В UTF-8 нет прямого сопоставления 1 байта с 1 символом, поскольку возможно, что символ будет использовать более 1 байта.

Вы можете перейти от списка байтов к списку символов Юникода, используя метод декодирования. Метод декодирования попытается сопоставить список байтов или список чисел с их символами Юникода и вернуть список символов Юникода. Это может привести к ошибке, если в исходном списке байтов была ошибка или если для перечисленных байтов нет сопоставления.

Вы можете перейти от списка символов Юникода к списку байтов, используя метод encode. Метод encode попытается сопоставить каждый отдельный символ Юникода с одним или несколькими байтами в возвращаемом списке. Опять же, как и в случае с методом декодирования, может произойти сбой, если у вас есть символы, которые невозможно отобразить в используемой вами таблице.

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

Читайте также: