сначала, я использую только python 3.1 в эти дни; его центральная заслуга состоит в том, чтобы иметь неоднозначные байтовые строки из объектов Юникода. это делает подавляющее большинство текстовых манипуляций намного более безопасными, чем это имело место. взвешивая триллионы вопросов пользователей относительно проблем с кодированием python 2.x, соглашение python 2.1 u'äbc
было просто ошибкой; с явным bytes
и bytearray
, жизнь становится намного проще.
Во-вторых, если py3k не ваш вкус, попробуйте пойти с from __future__ import unicode_literals
, так как это будет имитировать поведение py3k на python 2.6 и 2.7. эта вещь избегала бы (легко совершенной) ошибки, которую вы делали, говоря print 'exámple'.upper()
. по существу, это то же самое, что и в py3k: print('exámple'.encode('utf-8').upper())
.сравнить эти версии (для py3k):
print('exámple'.encode('utf-8').upper())
print('exámple'.encode('utf-8').upper().decode('utf-8'))
print('exámple'.upper())
Первый из них, в основном, то, что вы делали, когда использовал голую строку 'exámple'
, если вы установите кодировку по умолчанию для utf-8
(в соответствии с произнесением BDFL, установкой по умолчанию кодирование во время выполнения - плохая идея, поэтому в py2 вам придется обмануть его, сказав import sys; reload(sys); sys.setdefaultencoding('utf-8')
; я представляю лучшее решение для py3k ниже). когда вы смотрите на выходе из этих трех линий:
b'EX\xc3\xa1MPLE'
EXáMPLE
EXÁMPLE
вы можете увидеть, что когда upper()
был применен к первому тексту, он действовал на байтах, а не символы. python позволяет использовать метод upper()
в байтах, но он определяется только для интерпретации байтов в US-ASCII. поскольку utf-8 использует значения в пределах 8 бит, но за пределами US-ASCII (от 128 до 255, которые не используются US-ASCII), на них не будет влиять upper()
, поэтому, когда мы декодируем обратно вторая строка, мы получаем, что нижний регистр á
. наконец, третья строка делает это правильно, и да, с удивлением, python, похоже, знает, что Á
- это буква верхнего регистра, соответствующая á
. я побежал быстрый тест, чтобы увидеть, какие символы питона 3 не конвертировать между заглавными и строчными буквами:
for cid in range(3000):
my_chr = chr(cid)
if my_chr == my_chr.upper() and my_chr == my_chr.lower():
say(my_chr)
просматривал список показывает очень мало числа случаев латинских, кириллических или греческих буквы; большая часть выходных данных - неевропейские символы и знаки препинания. единственными символами, которые я обнаружил, что питон ошибался, - это Ԥ/ԥ (\ u0524, \ u0525, 'cyrillic {capital | small} letter pe с descender'), так что пока вы остаетесь за пределами латинских Extended-X блоков (проверьте их, они могут дать сюрпризы), вы можете использовать этот метод. конечно, я не проверял правильность отображений.
Наконец, вот что я вложил в мой раздел загрузки приложения py3k: метод, который переопределяет кодировку sys.stdout
, видит с цифровыми символьными ссылками (NCRs) как резерв; это приводит к тому, что печать на стандартный вывод никогда не вызовет ошибку кодирования в юникоде. когда я работаю на ubuntu, _sys.stdout.encoding
is utf-8
; когда одна и та же программа запускается в окнах, это может быть что-то странное, как cp850
. вывод может выглядеть starnge, но приложение работает без увеличения исключения на этих тусклых терминалах.
#===========================================================================================================
# MAKE STDOUT BEHAVE IN A FAILSAFE MANNER
#-----------------------------------------------------------------------------------------------------------
def _harden_stdout():
"""Ensure that unprintable output to STDOUT does not cause encoding errors; use XML character references
so any kind of output gets a chance to render in a decipherable way."""
global _sys_TRM
_sys.stdout = _sys_TRM = _sys_io.TextIOWrapper(
_sys.stdout.buffer,
encoding = _sys.stdout.encoding,
errors = 'xmlcharrefreplace',
line_buffering = true)
#...........................................................................................................
_harden_stdout()
еще один совет: при тестировании, всегда пытаются print repr(x)
или нечто подобное, что раскрывает личность x
. все виды недоразумений могут возникнуть, если вы только print x
в py2 и x
- это либо строка октета, либо объект unicode. это очень озадачивает и склонно вызывать много царапин на голове. как я уже сказал, постарайтесь, по крайней мере, перейти к py26 с тем, что из будущего ввоза букв Unicode.
и закрыть, ссылаясь на цитату: "Символ Лефковиц говорит, что лучше в своей статье Encoding:
I believe that in the context of this discussion, the term "string" is meaningless. There is text, and there is byte-oriented data (which may very well represent text, but is not yet converted to it). In Python types, Text is unicode. Data is str. The idea of "non-Unicode text" is just a programming error waiting to happen."
обновление: только что питон 3 правильно преобразует S Строчная латинская буква LONG S к S, когда верхний регистр аккуратным. !
py3k делает это правильно – SilentGhost