我仍然不完全理解python的unicode和str类型是如何工作的。注意:我在Python 2中工作,据我所知,Python 3对同一问题采用了完全不同的方法。
我所知道的:
str
是一个较老的野兽,可以保存由历史迫使我们使用的太多编码之一编码的字符串。
unicode
是一种更标准化的方式,可以使用包含所有可能字符,表情符号,狗粪等小图片的巨大表格来表示字符串。
decode
函数将字符串转换为unicode,encode
则反过来。
如果我在python的shell中,只需说:
>>> my_string = "some string"
然后my_string
是在str
中编码的ascii
变量(并且,因为ascii是utf-8的子集,所以它也在utf-8
中编码)。< / p>
因此,例如,我可以通过说出其中一行来将其转换为unicode
变量:
>>> my_string.decode('ascii')
u'some string'
>>> my_string.decode('utf-8')
u'some string'
我不知道:
Python如何处理在shell中传递的非ascii字符串,并且知道这一点,保存单词"kožušček"
的正确方法是什么?
例如,我可以说
>>> s1 = 'kožušček'
在哪种情况下s1
成为我无法转换为str
的{{1}}个实例:
unicode
现在,我自然无法用>>> s1='kožušček'
>>> s1
'ko\x9eu\x9a\xe8ek'
>>> print s1
kožušček
>>> s1.decode('ascii')
Traceback (most recent call last):
File "<pyshell#23>", line 1, in <module>
s1.decode('ascii')
UnicodeDecodeError: 'ascii' codec can't decode byte 0x9e in position 2: ordinal not in range(128)
解码字符串,但我应该使用什么编码?毕竟,我的ascii
会返回sys.getdefaultencoding()
!在提供行ascii
时,Python使用哪种编码来编码s1
?
我的另一个想法是说
s1=kožušček
但是,当我打印>>> s2 = u'kožušček'
时,我得到了
s2
这意味着Python丢失了整个字母。有人可以向我解释一下吗?
答案 0 :(得分:7)
str
个对象包含 bytes 。那些字节代表Python的内容并没有规定。如果您生成了ASCII兼容字节,则可以将它们解码为ASCII。如果它们包含表示UTF-8数据的字节,则它们可以如此解码。如果它们包含表示图像的字节,那么您可以解码该信息并在某处显示图像。在repr()
对象上使用str
时,Python将保留任何ASCII可打印的字节,其余字节将转换为转义序列;这使得即使在仅限ASCII的环境中也可以调试这些信息。
运行交互式解释器的终端或控制台将字节写入Python键入时从中读取的stdin
流。这些字节根据该终端或控制台的配置进行编码。
在您的情况下,您的控制台很可能将您输入的输入编码为Windows代码页。您需要找出确切的代码页并使用该编解码器来解码字节。代码页1252似乎适合:
>>> print 'ko\x9eu\x9a\xe8ek'.decode('cp1252')
kožušèek
当您打印那些相同的字节时,您的控制台正在读取这些字节并在已配置的相同编解码器中解释它们。
Python可以告诉你它认为你的控制台设置的编解码器;它尝试检测Unicode文字的此信息,其中必须为您解码输入。它使用locale.getpreferredencoding()
function来确定这一点,sys.stdin
和sys.stdout
对象具有encoding
属性;我的设置为UTF-8:
>>> import sys
>>> sys.stdin.encoding
'UTF-8'
>>> import locale
>>> locale.getpreferredencoding()
'UTF-8'
>>> 'kožušèek'
'ko\xc5\xbeu\xc5\xa1\xc3\xa8ek'
>>> u'kožušèek'
u'ko\u017eu\u0161\xe8ek'
>>> print u'kožušèek'
kožušèek
因为我的终端已经配置为UTF-8并且Python检测到了这一点,所以使用Unicode文字u'...'
可以正常工作。数据由Python自动解码。
为什么你的控制台丢失了一封我不知道的信件;我必须访问你的控制台并进行更多实验,查看print repr(s2)
的输出,并测试0x00和0xFF之间的所有字节,看看它是否在控制台的输入或输出端。< / p>
我建议您阅读Python和Unicode:
答案 1 :(得分:2)
您的系统不一定使用sys.getdefaultencoding()
编码;它只是在转换时使用的默认值而不告诉它编码,如:
>>> sys.getdefaultencoding()
'ascii'
>>> unicode(s1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 2: ordinal not in range(128)
Python对您的系统区域设置的想法在the locale
module:
>>> import locale
>>> locale.getdefaultlocale()
('en_US', 'UTF-8')
>>> locale.getpreferredencoding()
'UTF-8'
使用这个我们可以解码字符串:
>>> u1=s1.decode(locale.getdefaultlocale()[1])
>>> u1
u'ko\u017eu\u0161\u010dek'
>>> print u1
kožušček
有可能没有设置区域设置,就像'C'
区域设置的情况一样。这可能会导致报告的编码为None
,即使默认值为'ascii'
。正常情况下,确定这一点是setlocale
的工作,getpreferredencoding
会自动调用。我建议在你的程序启动时调用它一次并保存返回的值以供所有进一步使用。用于文件名的编码也可能是另一种情况,在sys.getfilesystemencoding()中报告。
Python内部默认编码由the site
module设置,其中包含:
def setencoding():
"""Set the string encoding used by the Unicode implementation. The
default is 'ascii', but if you're willing to experiment, you can
change this."""
encoding = "ascii" # Default value set by _PyUnicode_Init()
if 0:
# Enable to support locale aware default string encodings.
import locale
loc = locale.getdefaultlocale()
if loc[1]:
encoding = loc[1]
if 0:
# Enable to switch off string to Unicode coercion and implicit
# Unicode to string conversion.
encoding = "undefined"
if encoding != "ascii":
# On Non-Unicode builds this will raise an AttributeError...
sys.setdefaultencoding(encoding) # Needs Python Unicode build !
因此,如果您希望在每次运行Python时都默认设置它,则可以先将if 0
更改为if 1
。