unicode.md
1> **Источник:** https://python-all.ru/3.2/howto/unicode.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Руководство по Unicode89| Версия: | 1.12 |10| --- | --- |1112В этом HOWTO рассматривается поддержка Unicode в Python и объясняются различные проблемы, с которыми люди часто сталкиваются при работе с Unicode.1314## Введение в Unicode1516### История кодировок символов1718В 1968 году был стандартизирован American Standard Code for Information Interchange, более известный под аббревиатурой ASCII. ASCII определил числовые коды для различных символов, причем числовые значения варьировались от 0 до 127. Например, строчная буква 'a' получила код 97.1920ASCII был стандартом, разработанным в США, поэтому он определял только символы без диакритических знаков. Буква 'e' была, а 'é' или 'Í' – нет. Это означало, что языки, требующие диакритических знаков, не могли быть точно представлены в ASCII. (На самом деле отсутствие диакритических знаков имеет значение и для английского, в котором есть такие слова, как 'naïve' и 'café', а некоторые издательства требуют написания вроде 'coöperate'.)2122Некоторое время люди просто писали программы, которые не отображали диакритические знаки. Помню, как смотрел на программы на Apple \]\[ BASIC, опубликованные во франкоязычных изданиях в середине 1980-х, в которых были такие строки:2324```python25PRINT "FICHIER EST COMPLETE."26PRINT "CARACTERE NON ACCEPTE."27```2829Эти сообщения должны содержать диакритические знаки, и они выглядят неправильно для того, кто умеет читать по-французски.3031В 1980-х почти все персональные компьютеры были 8-битными, то есть байты могли хранить значения от 0 до 255. Коды ASCII доходили только до 127, поэтому некоторые машины присваивали значения от 128 до 255 символам с диакритическими знаками. Однако разные машины имели разные коды, что приводило к проблемам при обмене файлами. В конце концов появилось несколько часто используемых наборов значений для диапазона 128–255. Одни из них были настоящими стандартами, определёнными Международной организацией по стандартизации, а другие – *de facto* соглашениями, созданными той или иной компанией и получившими распространение.3233255 символов – не так много. Например, невозможно уместить одновременно символы с диакритикой, используемые в Западной Европе, и кириллицу для русского языка в диапазон 128–255, потому что таких символов больше 127.3435Можно было записывать файлы, используя разные кодировки (все русские файлы в кодировке KOI8, все французские файлы в другой кодировке Latin1), но что, если нужно было написать французский документ, цитирующий русский текст? В 1980-х люди начали искать решение этой проблемы, и началась работа по стандартизации Unicode.3637Изначально Unicode использовал 16-битные символы вместо 8-битных. 16 бит дают 2^16 = 65 536 различных значений, что позволяет представить множество символов из самых разных алфавитов; первоначальная цель заключалась в том, чтобы Unicode включал алфавиты всех языков человечества. Однако оказалось, что даже 16 бит недостаточно для достижения этой цели, и современная спецификация Unicode использует более широкий диапазон кодов: от 0 до 1 114 111 (`0x10FFFF` в 16-ричной системе).3839Существует связанный стандарт ISO – ISO 10646. Unicode и ISO 10646 изначально были разными проектами, но спецификации были объединены в версии Unicode 1.1.4041(Это обсуждение истории Unicode сильно упрощено. Не думаю, что среднестатистическому программисту на Python нужно беспокоиться об исторических деталях; обращайтесь к сайту консорциума Unicode, указанному в разделе «Ссылки», за дополнительной информацией.)4243### Определения4445**Символ** – это наименьший возможный компонент текста. 'A', 'B', 'C' и т.д. – всё это разные символы. Также как 'È' и 'Í'. Символы – это абстракции, и они варьируются в зависимости от языка или контекста. Например, символ ома (Ω) обычно рисуется очень похоже на заглавную букву омега (Ω) в греческом алфавите (в некоторых шрифтах они могут даже совпадать), но это два разных символа с разными значениями.4647Стандарт Unicode описывает, как символы представляются с помощью **кодовых точек**. Кодовая точка – это целое число, обычно обозначаемое в 16-ричной системе. В стандарте кодовая точка записывается в нотации `U+12CA`, что означает символ со значением `0x12ca` (4 810 в десятичной). Стандарт Unicode содержит множество таблиц, перечисляющих символы и соответствующие им кодовые точки:4849```text500061 'a'; LATIN SMALL LETTER A510062 'b'; LATIN SMALL LETTER B520063 'c'; LATIN SMALL LETTER C53...54007B '{'; LEFT CURLY BRACKET55```5657Строго говоря, из этих определений следует, что бессмысленно говорить «это символ `U+12CA`». `U+12CA` – это кодовая точка, которая представляет некоторый конкретный символ; в данном случае она представляет символ «ETHIOPIC SYLLABLE WI». В неформальном контексте это различие между кодовыми точками и символами иногда забывается.5859Символ отображается на экране или на бумаге с помощью набора графических элементов, который называется **глифом**. Глиф для заглавной A, например, представляет собой две диагональные и одну горизонтальную черту, хотя точные детали зависят от используемого шрифта. Большинству кода на Python не нужно беспокоиться о глифах; определение правильного глифа для отображения обычно является задачей GUI-инструментария или рендерера шрифтов терминала.6061### Кодировки6263Подытожим предыдущий раздел: Unicode-строка – это последовательность кодовых точек, которые представляют собой числа от 0 до `0x10FFFF` (1 114 111 в десятичной системе). Эта последовательность должна быть представлена в памяти в виде набора байтов (то есть значений от 0 до 255). Правила преобразования Unicode-строки в последовательность байтов называются **кодировкой**.6465Первая кодировка, которая может прийти в голову – это массив 32-битных целых чисел. В этом представлении строка «Python» будет выглядеть так:6667```text68 P y t h o n690x50 00 00 00 79 00 00 00 74 00 00 00 68 00 00 00 6f 00 00 00 6e 00 00 0070 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 2371```7273Такое представление интуитивно понятно, но его использование порождает ряд проблем.74751. Оно не является переносимым: разные процессоры по-разному упорядочивают байты.762. Это очень расточительно с точки зрения пространства. В большинстве текстов основная часть кодовых точек меньше 127 или меньше 255, поэтому много места занимают байты `0x00`. Приведённая выше строка занимает 24 байта по сравнению с 6 байтами, необходимыми для представления в ASCII. Увеличение использования оперативной памяти не так важно (настольные компьютеры имеют гигабайты RAM, а строки обычно не настолько велики), но увеличение использования диска и пропускной способности сети в 4 раза нетерпимо.773. Она несовместима с существующими функциями C, такими как `strlen()`, поэтому пришлось бы использовать новое семейство функций для работы с широкими строками.784. Многие интернет-стандарты определены в терминах текстовых данных и не могут обрабатывать содержимое с встроенными нулевыми байтами.7980Обычно люди не используют эту кодировку, предпочитая другие кодировки, которые более эффективны и удобны. UTF-8, вероятно, самая распространённая поддерживаемая кодировка; она будет рассмотрена ниже.8182Кодировки не обязаны обрабатывать все возможные символы Unicode, и большинство кодировок этого не делают. Правила преобразования строки Unicode в кодировку ASCII, например, просты; для каждой кодовой точки:83841. Если кодовая точка \< 128, каждый байт равен значению кодовой точки.852. Если кодовая точка равна 128 или больше, Unicode-строка не может быть представлена в этой кодировке. (В этом случае Python возбуждает исключение [`UnicodeEncodeError`](https://python-all.ru/3.2/library/exceptions.html#UnicodeEncodeError).)8687Latin-1, также известная как ISO-8859-1, является аналогичной кодировкой. Кодовые точки Unicode 0–255 идентичны значениям Latin-1, поэтому преобразование в эту кодировку просто требует преобразования кодовых точек в байтовые значения; если встречается кодовая точка больше 255, строка не может быть закодирована в Latin-1.8889Кодировки не обязательно должны быть простыми однозначными отображениями, как Latin-1. Рассмотрим EBCDIC от IBM, которая использовалась на мейнфреймах IBM. Значения букв не были в одном блоке: от 'a' до 'i' имели значения от 129 до 137, а от 'j' до 'r' – от 145 до 153. Если бы вы хотели использовать EBCDIC в качестве кодировки, вам, вероятно, пришлось бы использовать какую-нибудь таблицу поиска для выполнения преобразования, но это в значительной степени внутренняя деталь.9091UTF-8 – одна из наиболее часто используемых кодировок. UTF расшифровывается как «Unicode Transformation Format», а цифра '8' означает, что в кодировке используются 8-битные числа. (Существуют также кодировки UTF-16 и UTF-32, но они используются реже, чем UTF-8.) UTF-8 использует следующие правила:92931. Если кодовая точка \< 128, она представляется соответствующим значением байта.942. Если кодовая точка \>= 128, она преобразуется в последовательность из двух, трёх или четырёх байт, причём каждый байт находится в диапазоне от 128 до 255.9596UTF-8 обладает несколькими удобными свойствами:97981. Она может обрабатывать любую кодовую точку Юникода.992. Unicode-строка преобразуется в строку байтов, не содержащую встроенных нулевых байтов. Это позволяет избежать проблем с порядком байтов и означает, что строки UTF-8 могут обрабатываться функциями C, такими как `strcpy()`, и передаваться по протоколам, которые не могут обрабатывать нулевые байты.1003. Любая строка ASCII также является корректным текстом UTF-8.1014. UTF-8 довольно компактна; большинство часто используемых символов можно представить одним или двумя байтами.1025. Если байты повреждены или потеряны, можно определить начало следующей UTF-8-кодовой точки и восстановить синхронизацию. Кроме того, маловероятно, что случайные 8-битные данные будут выглядеть как корректный UTF-8.103104### Ссылки105106The [Unicode Consortium site](https://python-all.ru/3.2/howto/unicode.html) has character charts, a glossary, and PDF versions of the Unicode specification. Be prepared for some difficult reading. [A chronology](https://python-all.ru/3.2/howto/unicode.html) of the origin and development of Unicode is also available on the site.107108To help understand the standard, Jukka Korpela has written [an introductory guide](https://python-all.ru/3.2/howto/unicode.html) to reading the Unicode character tables.109110Ещё одна [хорошая вводная статья](https://python-all.ru/3.2/howto/unicode.html) была написана Джоэлом Спольски. Если это введение не прояснило для вас ситуацию, попробуйте прочитать эту альтернативную статью, прежде чем продолжать.111112Wikipedia entries are often helpful; see the entries for “[character encoding](https://python-all.ru/3.2/howto/unicode.html)” and [UTF-8](https://python-all.ru/3.2/howto/unicode.html), for example.113114## Поддержка Юникода в Python115116Теперь, когда вы освоили основы Юникода, давайте рассмотрим возможности Python по работе с ним.117118### Тип строки119120Начиная с Python 3.0, в языке есть тип [`str`](https://python-all.ru/3.2/library/functions.html#str), который содержит символы Unicode. Это означает, что любая строка, созданная с помощью `"unicode rocks!"`, `'unicode rocks!'` или синтаксиса тройных кавычек, хранится как Unicode.121122Чтобы вставить не-ASCII символ Unicode, например, любые буквы с диакритическими знаками, можно использовать управляющие последовательности в строковых литералах следующим образом:123124```python125>>> "\N{GREEK CAPITAL LETTER DELTA}" # Использование имени символа126'\u0394'127>>> "\u0394" # Использование 16-битного шестнадцатеричного значения128'\u0394'129>>> "\U00000394" # Использование 32-битного шестнадцатеричного значения130'\u0394'131```132133Кроме того, можно создать строку с помощью метода [`decode()`](https://python-all.ru/3.2/library/stdtypes.html#bytes.decode) объекта [`bytes`](https://python-all.ru/3.2/library/functions.html#bytes). Этот метод принимает аргумент *encoding*, такой как `UTF-8`, и, опционально, аргумент *errors*.134135Аргумент *errors* задаёт реакцию, когда входную строку невозможно преобразовать в соответствии с правилами кодировки. Допустимые значения этого аргумента: `'strict'` (возбуждает исключение [`UnicodeDecodeError`](https://python-all.ru/3.2/library/exceptions.html#UnicodeDecodeError)), `'replace'` (использует `U+FFFD`, `REPLACEMENT CHARACTER`) или `'ignore'` (просто исключает символ из Unicode-результата). Следующие примеры показывают различия:136137```python138>>> b'\x80abc'.decode("utf-8", "strict") 139Traceback (most recent call last):140 ...141UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 0:142 invalid start byte143>>> b'\x80abc'.decode("utf-8", "replace")144'\ufffdabc'145>>> b'\x80abc'.decode("utf-8", "ignore")146'abc'147```148149(В этом примере кода заменяющий символ Unicode заменён вопросительным знаком, поскольку на некоторых системах он может не отображаться.)150151Кодировки задаются строками, содержащими имя кодировки. Python 3.2 поставляется примерно со 100 различными кодировками; см. [*Standard Encodings*](https://python-all.ru/3.2/library/codecs.html#standard-encodings) в Python Library Reference для полного списка. Некоторые кодировки имеют несколько имён; например, `'latin-1'`, `'iso_8859_1'` и `'8859`‘ – все синонимы одной и той же кодировки.152153Односимвольные Unicode-строки также можно создать с помощью встроенной функции [`chr()`](https://python-all.ru/3.2/library/functions.html#chr), которая принимает целые числа и возвращает Unicode-строку длиной 1, содержащую соответствующую кодовую точку. Обратная операция – встроенная функция [`ord()`](https://python-all.ru/3.2/library/functions.html#ord), которая принимает односимвольную Unicode-строку и возвращает значение кодовой точки:154155```python156>>> chr(57344)157'\ue000'158>>> ord('\ue000')15957344160```161162### Преобразование в байты163164Противоположный метод для [`bytes.decode()`](https://python-all.ru/3.2/library/stdtypes.html#bytes.decode) – это [`str.encode()`](https://python-all.ru/3.2/library/stdtypes.html#str.encode), который возвращает [`bytes`](https://python-all.ru/3.2/library/functions.html#bytes)-представление строки Unicode, закодированное в указанной кодировке *encoding*. Параметр *errors* тот же, что и в методе [`decode()`](https://python-all.ru/3.2/library/stdtypes.html#bytes.decode), с одним дополнительным значением: помимо `'strict'`, `'ignore'` и `'replace'` (который в данном случае вставляет вопросительный знак вместо не кодируемого символа), можно также передать `'xmlcharrefreplace'`, использующий символьные ссылки XML. Следующий пример показывает различные результаты:165166```python167>>> u = chr(40960) + 'abcd' + chr(1972)168>>> u.encode('utf-8')169b'\xea\x80\x80abcd\xde\xb4'170>>> u.encode('ascii') 171Traceback (most recent call last):172 ...173UnicodeEncodeError: 'ascii' codec can't encode character '\ua000' in174 position 0: ordinal not in range(128)175>>> u.encode('ascii', 'ignore')176b'abcd'177>>> u.encode('ascii', 'replace')178b'?abcd?'179>>> u.encode('ascii', 'xmlcharrefreplace')180b'ꀀabcd޴'181```182183Низкоуровневые процедуры для регистрации и доступа к доступным кодировкам находятся в модуле [`codecs`](https://python-all.ru/3.2/library/codecs.html#module-codecs). Однако функции кодирования и декодирования, возвращаемые этим модулем, обычно слишком низкоуровневые для удобного использования, поэтому я не буду описывать модуль [`codecs`](https://python-all.ru/3.2/library/codecs.html#module-codecs) здесь. Если вам нужно реализовать совершенно новую кодировку, вам придётся изучить интерфейсы модуля [`codecs`](https://python-all.ru/3.2/library/codecs.html#module-codecs), но реализация кодировок – специализированная задача, которая также не будет рассмотрена здесь. Обратитесь к документации Python, чтобы узнать больше об этом модуле.184185### Литералы Unicode в исходном коде Python186187В исходном коде Python конкретные кодовые точки Unicode можно записать с помощью управляющей последовательности `\u`, за которой следуют четыре шестнадцатеричные цифры, задающие кодовую точку. Управляющая последовательность `\U` аналогична, но ожидает восемь шестнадцатеричных цифр, а не четыре:188189```python190>>> s = "a\xac\u1234\u20ac\U00008000"191... # ^^^^ двузначная шестнадцатеричная escape-последовательность192... # ^^^^^^ четырёхзначная Unicode escape-последовательность193... # ^^^^^^^^^^ восьмизначная Unicode escape-последовательность194>>> [ord(c) for c in s]195[97, 172, 4660, 8364, 32768]196```197198Использование управляющих последовательностей для кодовых точек больше 127 допустимо в небольших количествах, но становится утомительным, если используется много символов с диакритическими знаками, как в программе с сообщениями на французском или другом языке, использующем такие знаки. Можно также собирать строки с помощью встроенной функции [`chr()`](https://python-all.ru/3.2/library/functions.html#chr), но это ещё более кропотливо.199200В идеале хотелось бы иметь возможность записывать литералы в естественной кодировке вашего языка. Тогда можно было бы редактировать исходный код Python в любимом редакторе, который будет отображать символы с диакритическими знаками естественно, а при выполнении программы будут использоваться правильные символы.201202По умолчанию Python поддерживает запись исходного кода в UTF-8, но можно использовать почти любую кодировку, если объявить используемую кодировку. Это делается путём включения специального комментария в первую или вторую строку исходного файла:203204```python205#!/usr/bin/env python206# -*- coding: latin-1 -*-207208u = 'abcdé'209print(ord(u[-1]))210```211212Синтаксис вдохновлён нотацией Emacs для указания переменных, локальных для файла. Emacs поддерживает множество различных переменных, но Python поддерживает только «coding». Символы `-*-` указывают Emacs, что комментарий особенный; для Python они не имеют значения, но являются соглашением. Python ищет в комментарии `coding: name` или `coding=name`.213214Если такой комментарий не включён, по умолчанию будет использоваться кодировка UTF-8, как уже упоминалось. См. также [**PEP 263**](https://python-all.ru/3.2/howto/unicode.html) для получения дополнительной информации.215216### Свойства Unicode217218Спецификация Unicode включает базу данных информации о кодовых точках. Для каждой определённой кодовой точки информация включает имя символа, его категорию, числовое значение, если применимо (Unicode содержит символы, представляющие римские цифры и дроби, такие как одна треть и четыре пятых). Существуют также свойства, связанные с использованием кодовой точки в двунаправленном тексте и другие свойства, относящиеся к отображению.219220Следующая программа выводит некоторую информацию о нескольких символах и печатает числовое значение одного конкретного символа:221222```python223import unicodedata224225u = chr(233) + chr(0x0bf2) + chr(3972) + chr(6000) + chr(13231)226227for i, c in enumerate(u):228 print(i, '%04x' % ord(c), unicodedata.category(c), end=" ")229 print(unicodedata.name(c))230231# Получить числовое значение второго символа232print(unicodedata.numeric(u[1]))233```234235При запуске выводится:236237```text2380 00e9 Ll LATIN SMALL LETTER E WITH ACUTE2391 0bf2 No TAMIL NUMBER ONE THOUSAND2402 0f84 Mn TIBETAN MARK HALANTA2413 1770 Lo TAGBANWA LETTER SA2424 33af So SQUARE RAD OVER S SQUARED2431000.0244```245246Коды категорий – это сокращения, описывающие природу символа. Они сгруппированы в категории, такие как «Letter» (Буква), «Number» (Число), «Punctuation» (Знак препинания) или «Symbol» (Символ), которые в свою очередь разбиваются на подкатегории. Взяв коды из приведённого выше вывода, `'Ll'` означает «Letter, lowercase» (Буква, строчная), `'No'` означает «Number, other» (Число, прочее), `'Mn'` – «Mark, nonspacing» (Знак, некомбинирующий), а `'So'` – «Symbol, other» (Символ, прочее). См. \<[http://www.unicode.org/reports/tr44/#General\_Category\_Values](https://python-all.ru/3.2/howto/unicode.html)\> для списка кодов категорий.247248### Ссылки249250Тип [`str`](https://python-all.ru/3.2/library/functions.html#str) описан в справочнике по библиотеке Python в разделе [*Sequence Types – str, bytes, bytearray, list, tuple, range*](https://python-all.ru/3.2/library/stdtypes.html#typesseq).251252Документация модуля [`unicodedata`](https://python-all.ru/3.2/library/unicodedata.html#module-unicodedata).253254Документация модуля [`codecs`](https://python-all.ru/3.2/library/codecs.html#module-codecs).255256Марк-Андре Лембург сделал доклад на EuroPython 2002 под названием «Python and Unicode». PDF-версия его слайдов доступна по адресу \<[http://downloads.egenix.com/python/Unicode-EPC2002-Talk.pdf](https://python-all.ru/3.2/howto/unicode.html)\> и представляет собой отличный обзор дизайна возможностей Python для работы с Unicode (основанный на Python 2, где тип строк Unicode называется `unicode`, а литералы начинаются с `u`).257258## Чтение и запись данных Unicode259260После написания кода, работающего с данными Unicode, следующая проблема – ввод/вывод. Как передавать строки Unicode в программу и как преобразовывать Unicode в форму, подходящую для хранения или передачи?261262Возможно, вам может не понадобиться ничего делать в зависимости от источников ввода и мест назначения вывода; следует проверить, поддерживают ли библиотеки, используемые в вашем приложении, Unicode нативно. Например, XML-парсеры часто возвращают данные в Unicode. Многие реляционные базы данных также поддерживают столбцы со значением Unicode и могут возвращать значения Unicode из SQL-запросов.263264Данные Unicode обычно преобразуются в определённую кодировку перед тем, как записываются на диск или отправляются через сокет. Можно выполнить всю работу самостоятельно: открыть файл, прочитать 8-битный объект bytes и преобразовать строку с помощью `bytes.decode(encoding)`. Однако ручной подход не рекомендуется.265266Одна из проблем – многобайтовая природа кодировок: один символ Unicode может быть представлен несколькими байтами. Если вы хотите читать файл частями произвольного размера (скажем, по 1 КБ или 4 КБ), нужно написать код обработки ошибок для случаев, когда в конце части считывается только часть байтов, кодирующих один символ Unicode. Одно из решений – прочитать весь файл в память, а затем выполнить декодирование, но это не позволяет работать с очень большими файлами; если нужно прочитать файл размером 2 ГБ, потребуется 2 ГБ ОЗУ. (Даже больше, на самом деле, поскольку хотя бы на мгновение в памяти должны находиться и закодированная строка, и её версия в Unicode.)267268Решением было бы использование низкоуровневого интерфейса декодирования для обработки случаев частичных кодировочных последовательностей. Работа по реализации этого уже выполнена за вас: встроенная функция [`open()`](https://python-all.ru/3.2/library/functions.html#open) может возвращать объект, подобный файловому, который предполагает, что содержимое файла находится в указанной кодировке, и принимает параметры Unicode для таких методов, как `read()` и `write()`. Это работает благодаря параметрам *encoding* и *errors* функции [`open()`](https://python-all.ru/3.2/library/functions.html#open), которые интерпретируются так же, как и в [`str.encode()`](https://python-all.ru/3.2/library/stdtypes.html#str.encode) и [`bytes.decode()`](https://python-all.ru/3.2/library/stdtypes.html#bytes.decode).269270Чтение Unicode из файла, таким образом, просто:271272```python273with open('unicode.rst', encoding='utf-8') as f:274 for line in f:275 print(repr(line))276```277278Также можно открывать файлы в режиме обновления, позволяющем как чтение, так и запись:279280```python281with open('test', encoding='utf-8', mode='w+') as f:282 f.write('\u4500 blah blah blah\n')283 f.seek(0)284 print(repr(f.readline()[:1]))285```286287Символ Юникода `U+FEFF` используется в качестве метки порядка байтов (BOM) и часто записывается первым символом файла, чтобы помочь автоматическому определению порядка байтов файла. Некоторые кодировки, например UTF-16, ожидают наличия BOM в начале файла; при использовании такой кодировки BOM автоматически записывается как первый символ и молча отбрасывается при чтении файла. Существуют варианты этих кодировок, такие как 'utf-16-le' и 'utf-16-be' для little-endian и big-endian соответственно, которые задают конкретный порядок байтов и не пропускают BOM.288289В некоторых областях также принято использовать «BOM» в начале файлов, закодированных в UTF-8; это название вводит в заблуждение, поскольку UTF-8 не зависит от порядка байтов. Метка просто объявляет, что файл закодирован в UTF-8. Используйте кодировку 'utf-8-sig', чтобы автоматически пропускать метку, если она присутствует, при чтении таких файлов.290291### Имена файлов в Unicode292293Большинство распространённых сегодня операционных систем поддерживают имена файлов, содержащие произвольные символы Unicode. Обычно это реализуется преобразованием строки Unicode в некоторую кодировку, которая зависит от системы. Например, Mac OS X использует UTF-8, тогда как Windows использует настраиваемую кодировку; в Windows Python использует имя «mbcs» для обозначения текущей настроенной кодировки. В системах Unix кодировка файловой системы будет доступна только при установке переменных среды `LANG` или `LC_CTYPE`; если они не установлены, кодировка по умолчанию – ASCII.294295Функция [`sys.getfilesystemencoding()`](https://python-all.ru/3.2/library/sys.html#sys.getfilesystemencoding) возвращает кодировку, используемую в текущей системе, на случай, если понадобится выполнить кодирование вручную, но обычно в этом нет особой необходимости. При открытии файла для чтения или записи можно просто передать строку Юникода в качестве имени файла, и она будет автоматически преобразована в нужную кодировку.296297```python298filename = 'filename\u4500abc'299with open(filename, 'w') as f:300 f.write('blah\n')301```302303Функции из модуля [`os`](https://python-all.ru/3.2/library/os.html#module-os), такие как [`os.stat()`](https://python-all.ru/3.2/library/os.html#os.stat), также принимают имена файлов в Юникоде.304305Функция [`os.listdir()`](https://python-all.ru/3.2/library/os.html#os.listdir), возвращающая имена файлов, порождает вопрос: должна ли она возвращать версию имён файлов в Unicode или должна возвращать bytes, содержащие закодированные версии? [`os.listdir()`](https://python-all.ru/3.2/library/os.html#os.listdir) будет делать и то, и другое в зависимости от того, предоставили ли вы путь к каталогу как bytes или строку Unicode. Если передать строку Unicode в качестве пути, имена файлов будут декодированы с использованием кодировки файловой системы и будет возвращён список строк Unicode, тогда как передача пути в виде bytes вернёт байтовые версии имён файлов. Например, предполагая, что кодировка файловой системы по умолчанию – UTF-8, запуск следующей программы:306307```python308fn = 'filename\u4500abc'309f = open(fn, 'w')310f.close()311312import os313print(os.listdir(b'.'))314print(os.listdir('.'))315```316317выдаст следующий результат:318319```python320amk:~$ python t.py321[b'.svn', b'filename\xe4\x94\x80abc', ...]322['.svn', 'filename\u4500abc', ...]323```324325Первый список содержит имена файлов в кодировке UTF-8, а второй список – версии в Unicode.326327Обратите внимание, что в большинстве случаев следует использовать API Unicode. API bytes следует использовать только в системах, где могут встречаться не декодируемые имена файлов, т.е. в системах Unix.328329### Советы по написанию программ с поддержкой Unicode330331В этом разделе приводятся некоторые рекомендации по написанию программного обеспечения, работающего с Unicode.332333Самый важный совет:334335> Программное обеспечение должно работать внутри только со строками Unicode, декодируя входные данные как можно раньше и кодируя вывод только в конце.336337Если попытаться написать функции обработки, которые принимают как строки Юникода, так и байтовые строки, программа будет уязвима для ошибок в местах, где используются строки разных типов. Автоматического кодирования или декодирования не происходит: например, при попытке выполнить `str + bytes` будет возбуждено исключение [`TypeError`](https://python-all.ru/3.2/library/exceptions.html#TypeError).338339При использовании данных из веб-браузера или другого ненадёжного источника распространённый приём – проверка строки на недопустимые символы перед использованием в генерируемой командной строке или сохранением в базе данных. Если это делается, следует проверять декодированную строку, а не закодированные байтовые данные; некоторые кодировки могут обладать интересными свойствами, такими как отсутствие биективности или полной совместимости с ASCII. Это особенно важно, если входные данные также задают кодировку, так как злоумышленник может выбрать хитрый способ скрыть вредоносный текст в закодированном потоке байтов.340341### Ссылки342343PDF-слайды презентации Марка-Андре Лембурга «Writing Unicode-aware Applications in Python» доступны по адресу \<[http://downloads.egenix.com/python/LSM2005-Developing-Unicode-aware-applications-in-Python.pdf](https://python-all.ru/3.2/howto/unicode.html)\> и обсуждают вопросы кодировок символов, а также то, как интернационализировать и локализовать приложение. Эти слайды охватывают только Python 2.x.344345## Благодарности346347Благодарности следующим людям, которые указали на ошибки или предложили улучшения для этой статьи: Nicholas Bastin, Marius Gedminas, Kent Johnson, Ken Krugler, Marc-André Lemburg, Martin von Löwis, Chad Whitacre.348