【问题标题】:Confused about unicode representations对 unicode 表示感到困惑
【发布时间】:2013-09-10 21:54:35
【问题描述】:

我对 Unicode 的十六进制表示感到困惑。 我有一个示例文件,其中包含一个数学积分符号字符。即U+222B 如果我 cat 文件或在 vi 中编辑它,我会显示一个积分符号。 该文件的十六进制转储显示其十六进制内容为 88e2 0aab

在 python 中,我可以创建一个完整的 unicode 字符并在我的终端上打印 p 渲染和整数符号。

>>> p=u'\u222b'
>>> p
u'\u222b'
>>> print p
∫

让我困惑的是我可以打开一个带有积分符号的文件,得到积分符号但十六进制内容不同。

>>> c=open('mycharfile','r').read()
>>> c
'\xe2\x88\xab\n'
>>> print c
∫

一个是 Unicode 对象,一个是纯字符串,但是对于同一个字符,这两个十六进制代码之间的关系是什么?我如何手动将一个转换为另一个?

【问题讨论】:

  • 0x222b = 8747 是代码点的整数,在 Unicode 中,与整数符号 相关联。当您将文本写入文件或通过网络发送时,它必须始终序列化为位——通常,八位字节(字节)是这里的首选单位。系列0xe20x880xab(或0b111000100b100010000b10101011二进制)是0x222b的UTF-8编码(en.wikipedia.org/wiki/UTF-8)。顺便说一句,第一个字节中的三个前导 1s 告诉您这个代码点是用三个字节编码的:UTF-8 既是可变宽度又是“同步”的。
  • 必填:bit.ly/unipain
  • bitly 链接看起来很有希望。还应该指出,Py3 中的 Unicode 处理比以前在 Py2 中要明智得多——以至于在决定使用哪个 Python 版本时,这一因素应该很重要。可悲的是,Py2 和 Py3 之间存在着不好的和持续的分裂,第三方库支持滞后。 Py3 的亮点在于旧的“ASCII 字符串”已经不复存在;您总是处理字节缓冲区(编码)或(Unicode)文本(解码)。它只是改变了概念/命名事物,但是编程很多关于概念和命名事物。
  • 除了概念和名称的改变之外,Py3 还具有不隐式转换字节和字符串的更安全的行为。尝试将它们连接起来,它会立即抱怨,这比 Py2 方法要好得多,它通常可以工作,但在默认编码无法转换时会失败。
  • 我仍然缺少一些东西。字节对从字符的十六进制编辑中包含的 88e2 0aab 反转,一个字符是返回,所以我们剩下 0xe2、0x88、0xab

标签: python unicode unicode-string


【解决方案1】:

纯字符串已使用 UTF-8 进行编码,这是以字节表示 Unicode 代码点的多种方式之一。 UTF-8 是一种多字节编码,它有一个非常有用的特性,即它是 ASCII 的超集 - 相同的字节编码 UTF-8 或 ASCII 中的任何 ASCII 字符。

在 Python 2.x 中,使用 Unicode 对象上的encode 方法对其进行编码,并使用decodeunicode 构造函数对其进行解码:

>>> u'\u222b'.encode('utf8')
'\xe2\x88\xab'
>>> '\xe2\x88\xab'.decode('utf8')
u'\u222b'
>>> unicode('\xe2\x88\xab', 'utf8')
u'\u222b'

print,当给定一个 Unicode 参数时,会对其进行隐式编码。在我的系统上:

>>> sys.stdout.encoding
'UTF-8'

有关print 行为的详细讨论,请参阅此答案: Why does Python print unicode characters when the default encoding is ASCII?

Python 3 处理事情的方式有点不同;此处记录了更改: http://docs.python.org/3.0/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit

【解决方案2】:

好的,我知道了。感谢您的回答。我想看看如何进行转换,而不是使用 Python 转换字符串。

转换以这种方式进行。

如果你有一个 unicode 字符,在我的例子中是一个整数符号。

八进制转储产生

echo -n "∫"|od -x
0000000 88e2 00ab

每个十六进制对都颠倒了,所以它真的意味着

e288ab00

第一个十六进制字符是 E。高位表示这是一个 Unicode 字符串,接下来的两位表示它是 3 个三个字节(16 位)来表示字符。 剩下的十六进制数字的前两位被丢弃(它们表示它们是 unicode。)完整的比特流是

111000101000100010101011

扔掉剩下的十六进制数字的前4位和前两位

0010001000101011

用十六进制重新表达

222B

你有它!

【讨论】:

  • “高位表示这是一个 Unicode 字符串”不太正确。它模糊了使用非 ASCII 字符与 UTF-8 特定编码细节之间的界限。更准确地说,高位意味着它是多字节编码的一部分;第一个 0 之前的前导 1 的数量告诉您编码中的总字节数(在这种情况下为 3)。你的实际处理是正确的,但我建议仔细阅读 Joel on Software 文章 Jongware 链接到。 Unicode 和编码是相关的概念,但不像这个措辞所暗示的那样可以互换。
猜你喜欢
  • 2012-03-02
  • 2019-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-13
  • 2012-07-22
  • 2013-05-13
相关资源
最近更新 更多