Весь ключ к таким проблемам кодирования заключается в понимании того, что в принципе существует два различных понятия "строка" : (1) строка из символов и (2) строка/ массив байт .Это различие в основном долгое время игнорировалось из-за исторической распространенности кодировок, содержащих не более 256 символов (ASCII, Latin-1, Windows-1252, Mac OS Roman ...): эти кодировки отображают набор общих символов вчисла от 0 до 255 (т.е. байты);относительно ограниченный обмен файлами до появления Интернета сделал эту ситуацию несовместимых кодировок допустимой, поскольку большинство программ могли игнорировать тот факт, что было несколько кодировок, если они производили текст, который оставался в одной и той же операционной системе: такие программы простообрабатывать текст как байты (через кодировку, используемую операционной системой).Правильное, современное представление должным образом разделяет эти две концепции строк, основываясь на следующих двух моментах:
Символы в основном не связаны с компьютерами :их можно нарисовать на доске, например, بايثون, 中 蟒 и ?.«Знаки» для машин также включают «инструкции рисования», такие как, например, пробелы, возврат каретки, инструкции по установке направления письма (для арабского языка и т. Д.), Ударения и т. Д. * очень большой список символов включенв стандарте Unicode ;он охватывает большинство известных символов.
С другой стороны, компьютерам необходимо каким-то образом представлять абстрактные символы: для этого они используют массивы байтов (числа от 0 до 255 включены), потому что их память поступает в байтовых блоках.Необходимый процесс, который преобразует символы в байты, называется encoding .Таким образом, компьютеру требуется кодировка для представления символов.Любой текст, присутствующий на вашем компьютере, кодируется (до его отображения), независимо от того, отправлен ли он на терминал (который ожидает символы, закодированные определенным образом), или сохранен в файле.Чтобы быть отображенными или правильно «понятыми» (скажем, интерпретатором Python), потоки байтов декодируются в символы. Несколько кодировок (UTF-8, UTF-16, ...) определены Unicode для его списка символов (Unicode, таким образом, определяет и список символов, и кодировки для этих символов - все еще есть места, где одинвидит выражение «кодировка Unicode» как способ обращения к вездесущему UTF-8, но это неверная терминология, поскольку Unicode обеспечивает множественные кодировки).
Таким образом, компьютерам необходимо внутренне представлять символы с байтами , и они делают это с помощью двух операций:
Кодировка : символы → байты
Декодирование : байты → символы
Некоторые кодировки не могут кодировать все символы (например, ASCII), в то время как (некоторые) кодировки Unicode позволяют кодировать все символы Unicode. Кодировка также не обязательно уникальна , поскольку некоторые символы могут быть представлены либо напрямую, либо в виде комбинации (например, базового символа и ударений).
Примечаниечто концепция newline добавляет уровень сложности , поскольку он может быть представлен различными (управляющими) символами, которые зависят от операционной системы (это причина для в Pythonуниверсальный режим чтения файла новой строки ).
Теперь то, что я назвал «символом» выше, - это то, что Unicode называет « воспринимаемым пользователем символом ».Один воспринимаемый пользователем символ иногда может быть представлен в Юникоде путем объединения частей символов (базовый символ, акценты,…), найденных с разными индексами в списке Юникод, которые называются " codepoints "- эти кодовые точки могут быть объединены вместе для формирования" кластера графем ".Unicode, таким образом, приводит кПервая концепция строки, состоящая из последовательности кодовых точек Unicode, которая находится между байтовой и символьной строками и которая ближе к последней. Я назову их « Unicode-строки » (как в Python 2).
В то время как Python может печатать строки (воспринимаемых пользователем) символов, Небайтные строки Python являются по существу последовательностями кодовых точек Unicode , а не воспринимаемыми пользователем символами. Значения кодовой точки - это те, которые используются в синтаксисе строки Unicode в Python \u
и \U
. Их не следует путать с кодировкой символа (и не должны иметь с ним никакой связи: кодовые точки Unicode могут кодироваться различными способами).
Это имеет важное следствие: длина строки Python (Unicode) - это количество кодовых точек, которое не , всегда число воспринимаемых пользователем символов : таким образом s = "\u1100\u1161\u11a8"; print(s, "len", len(s))
(Python 3) дает 각 len 3
, несмотря на то, что s
имеет один воспринимаемый пользователем (корейский) символ (потому что он представлен 3 кодами - даже если это не обязательно, как показывает print("\uac01")
). Однако во многих практических обстоятельствах длина строки равна количеству воспринимаемых пользователем символов, поскольку многие символы обычно хранятся в Python как единая кодовая точка Unicode.
В Python 2 строки Unicode называются… «строками Unicode» (тип unicode
, буквенная форма u"…"
), в то время как байтовые массивы являются «строками» (тип str
, где Например, массив байтов может быть построен из строковых литералов "…"
). В Python 3 строки Unicode просто называются «строками» (str
тип, буквенная форма "…"
), в то время как байтовые массивы являются «байтами» (bytes
тип, буквальная форма b"…"
) .
С этими несколькими ключевыми моментами вы сможете понять большинство вопросов, связанных с кодированием!
Обычно, когда вы печатаете u"…"
на терминале , вы не должны получать мусор: Python знает кодировку вашего терминала. Фактически вы можете проверить, какую кодировку ожидает терминал:
% python
Python 2.7.6 (default, Nov 15 2013, 15:20:37)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print sys.stdout.encoding
UTF-8
Если ваши входные символы могут быть закодированы с помощью кодировки терминала, Python сделает это и отправит соответствующие байты на ваш терминал без жалоб. Затем терминал сделает все возможное, чтобы отобразить символы после декодирования входных байтов (в худшем случае шрифт терминала не содержит некоторых символов и вместо этого напечатает какой-то пробел).
Если ваши входные символы не могут быть закодированы с помощью кодировки терминала, это означает, что терминал не настроен для отображения этих символов. Python будет жаловаться (в Python с UnicodeEncodeError
, поскольку символьная строка не может быть закодирована таким образом, который подходит вашему терминалу). Единственное возможное решение - использовать терминал, который может отображать символы (либо путем настройки терминала так, чтобы он принимал кодировку, которая может представлять ваши символы, либо с помощью другой программы терминала). Это важно при распространении программ, которые можно использовать в разных средах: печатаемые сообщения должны быть представлены в пользовательском терминале. Поэтому иногда лучше придерживаться строк, которые содержат только символы ASCII.
Однако, когда вы перенаправляете или перенаправляете вывод вашей программы, обычно невозможно узнать, какова входная кодировка принимающей программы, и приведенный выше код возвращает некоторую кодировку по умолчанию: Нет (Python 2.7) или UTF-8 (Python 3):
% python2.7 -c "import sys; print sys.stdout.encoding" | cat
None
% python3.4 -c "import sys; print(sys.stdout.encoding)" | cat
UTF-8
Однако кодирование stdin, stdout и stderr может быть установлено через переменную окружения PYTHONIOENCODING
, если необходимо:
% PYTHONIOENCODING=UTF-8 python2.7 -c "import sys; print sys.stdout.encoding" | cat
UTF-8
Если печать на терминал не дает ожидаемого результата, вы можете проверить правильность кодировки UTF-8, введенной вручную; например, ваш первый символ (\u001A
) не печатается, , если я не ошибаюсь .
На http://wiki.python.org/moin/PrintFails, вы можете найти решение, подобное следующему, для Python 2.x:
import codecs
import locale
import sys
# Wrap sys.stdout into a StreamWriter to allow writing unicode.
sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout)
uni = u"\u001A\u0BC3\u1451\U0001D10C"
print uni
Fили Python 3, вы можете проверить один из вопросов, заданных ранее в StackOverflow.