猿问

Python str与unicode类型

使用Python 2.7,我想知道使用type unicode代替真正的优势是什么str,因为它们似乎都可以容纳Unicode字符串。除了能够unicode使用转义字符在字符串中设置Unicode代码之外,还有什么特殊的原因\吗?:


使用以下命令执行模块:


# -*- coding: utf-8 -*-


a = 'á'

ua = u'á'

print a, ua

结果:á,á


编辑:


使用Python Shell进行更多测试:


>>> a = 'á'

>>> a

'\xc3\xa1'

>>> ua = u'á'

>>> ua

u'\xe1'

>>> ua.encode('utf8')

'\xc3\xa1'

>>> ua.encode('latin1')

'\xe1'

>>> ua

u'\xe1'

因此,该unicode字符串似乎是使用latin1而不是编码的utf-8,而原始字符串是使用utf-8?编码的。我现在更加困惑!:S


慕婉清6462132
浏览 1031回答 3
3回答

江户川乱折腾

unicode用于处理文本。文本是一个代码点序列,可能大于一个字节。文本可以被编码在一个特定的编码来表示文本作为原始字节(例如utf-8,latin-1...)。注意,这unicode 是没有编码的!python使用的内部表示形式是实现细节,只要它能够表示所需的代码点,您就不必在意它。相反,str在Python 2中是字节的简单序列。它不代表文字!您可以将其unicode视为某些文本的一般表示形式,可以用多种不同方式将其编码为通过表示的二进制数据序列str。注意:在Python 3中,unicode已重命名为,str并且bytes为普通字节序列提供了一种新类型。您可以看到一些差异:>>> len(u'à')  # a single code point1>>> len('à')   # by default utf-8 -> takes two bytes2>>> len(u'à'.encode('utf-8'))2>>> len(u'à'.encode('latin1'))  # in latin1 it takes one byte1>>> print u'à'.encode('utf-8')  # terminal encoding is utf-8à>>> print u'à'.encode('latin1') # it cannot understand the latin1 byte�请注意,使用时,str您可以对特定编码表示形式的单个字节进行较低级别的控制,而使用时,unicode您只能在代码点级别进行控制。例如,您可以执行以下操作:>>> 'àèìòù''\xc3\xa0\xc3\xa8\xc3\xac\xc3\xb2\xc3\xb9'>>> print 'àèìòù'.replace('\xa8', '')à�ìòù以前是有效的UTF-8,现在已经不复存在了。使用unicode字符串,您不能以结果字符串不是有效的unicode文本的方式进行操作。您可以删除代码点,将代码点替换为其他代码点等,但不能与内部表示混淆。

长风秋雁

Unicode和编码是完全不同的,无关的东西。统一码为每个字符分配一个数字ID:0x41→A0xE1→á0x414→Д因此,Unicode将数字0x41分配给A,将0xE1分配给á,将0x414分配给Д。即使是我使用的小箭头也有其Unicode数字,即0x2192。甚至表情符号都有其Unicode数字,?是0x1F602。您可以在此表中查找所有字符的Unicode数字。特别是,你可以找到前三个字符以上在这里,箭头在这里,和表情符号在这里。这些由Unicode分配给所有字符的数字称为代码点。所有这些的目的是提供一种明确引用每个字符的方法。例如,如果我说的是?,而不是说“你知道,这笑着哭的表情含泪”,我只能说Unicode代码点0x1F602。比较容易,对吧?请注意,Unicode代码点通常使用前导格式U+,然后将十六进制数字值填充为至少4位数字。因此,以上示例为U + 0041,U + 00E1,U + 0414,U + 2192,U + 1F602。Unicode代码点的范围从U + 0000到U + 10FFFF。那是1,114,112数字。这些数字中的2048个用于代理,因此,剩下1,112,064。这意味着,Unicode可以为1,112,064个不同的字符分配唯一的ID(代码点)。尚未将所有这些代码点都分配给一个字符,并且Unicode会连续扩展(例如,当引入新的表情符号时)。要记住的重要一点是,所有Unicode所做的就是为每个字符分配一个称为代码点的数字ID,以便于进行明确的引用。编码方式将字符映射到位模式。这些位模式用于表示计算机内存或磁盘上的字符。有许多不同的编码覆盖了字符的不同子集。在说英语的世界中,最常见的编码如下:ASCII码将128个字符(代码点U + 0000到U + 007F)映射到长度为7的位模式。例:a→1100001(0x61)您可以在此表中看到所有映射。ISO 8859-1(又名Latin-1)将191个字符(代码点U + 0020到U + 007E和U + 00A0到U + 00FF)映射到长度为8的位模式。例:a→01100001(0x61)á→11100001(0xE1)您可以在此表中看到所有映射。UTF-8将1,112,064个字符(所有现有的Unicode代码点)映射到长度为8、16、24或32位(即1、2、3或4个字节)的位模式。例:a→01100001(0x61)á→11000011 10100001(0xC3 0xA1)≠→11100010 10001001 10100000(0xE2 0x89 0xA0)?→11110000 10011111 10011000 10000010(0xF0 0x9F 0x98 0x82)UTF-8将字符编码为位字符串的方法在此处进行了很好的描述。Unicode和编码通过上面的示例,可以清楚地了解Unicode是如何有用的。例如,如果我是Latin-1,并且想解释一下á的编码,则无需说:“我使用aigu(或您将其称为上升条)将a编码为11100001”但我只能说:“我将U + 00E1编码为11100001”如果我是UTF-8,我可以说:“我又将U + 00E1编码为11000011 10100001”每个人都清楚知道我们指的是哪个角色。现在到经常出现的混乱的确,有时,如果将编码的位模式解释为二进制数,则与该字符的Unicode代码点相同。例如:ASCII编码一个为1100001,您可以解释为十六进制数0x61,和的Unicode代码点一个是U + 0061。Latin-1将á编码为11100001,可以将其解释为十六进制数字0xE1,而á的Unicode代码点是U + 00E1。当然,为了方便起见,已经对此进行了安排。但是您应该将其视为纯粹的巧合。用于表示内存中字符的位模式与该字符的Unicode代码点没有任何关联。甚至没人说您必须将11100001之类的字符串解释为二进制数。只需将其视为Latin-1用来编码字符á的位序列即可。回到您的问题您的Python解释器使用的编码为UTF-8。这是您的示例中发生的事情:例子1以下代码以UTF-8编码字符á。这将产生位字符串11000011 10100001,该位字符串将保存在变量中a。>>> a = 'á'当您查看的值时a,其内容11000011 10100001的格式为十六进制数字0xC3 0xA1,输出为'\xc3\xa1':>>> a'\xc3\xa1'例子2以下代码将á的Unicode代码点U + 00E1保存在变量中ua(我们不知道Python内部使用哪种数据格式在内存中表示代码点U + 00E1,这对我们来说并不重要):>>> ua = u'á'当您查看的值时ua,Python会告诉您它包含代码点U + 00E1:>>> uau'\xe1'例子3以下代码使用UTF-8对Unicode代码点U + 00E1(表示字符á)进行编码,这将导致位模式1100001110100001。同样,对于输出,该位模式也表示为十六进制数字0xC3 0xA1:>>> ua.encode('utf-8')'\xc3\xa1'例子4下面的代码使用Latin-1对Unicode代码点U + 00E1(代表字符á)进行编码,从而得到位模式11100001。对于输出,该位模式表示为十六进制数0xE1,巧合的是,其与初始字符相同。码点U + 00E1:>>> ua.encode('latin1')'\xe1'Unicode对象ua和Latin-1编码之间没有关系。á的代码点为U + 00E1,而á的Latin-1编码为0xE1(如果将编码的位模式解释为二进制数)纯属巧合。
随时随地看视频慕课网APP

相关分类

Python
我要回答