【问题标题】:String literal Vs Unicode literal Vs unicode type object - Memory representation字符串文字与 Unicode 文字与 Unicode 类型对象 - 内存表示
【发布时间】:2017-11-05 04:31:33
【问题描述】:

Python 2.x doc 说,

Unicode 字符串是一个代码点序列

Unicode 字符串表示为 unicode 类型的实例

>>> ThisisNotUnicodeString = 'a정정????' # What is the memory representation?
>>> ThisisNotUnicodeString
'a\xec\xa0\x95\xec\xa0\x95\xf0\x9f\x92\x9b'
>>> type(ThisisNotUnicodeString)
<type 'str'>
>>> a = u'a정정????' # Which encoding technique used to represent in memory? utf-8?
>>> a
u'a\uc815\uc815\U0001f49b'
>>> type(a)
<type 'unicode'>
>>> b = unicode('a정정????', 'utf-8')
>>> b
u'a\uc815\uc815\U0001f49b'
>>> c = unicode('a정정????', 'utf-16')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/encodings/utf_16.py", line 16, in decode
    return codecs.utf_16_decode(input, errors, True)
UnicodeDecodeError: 'utf16' codec can't decode byte 0x9b in position 10: truncated data
>>> 

问题:

1) ThisisNotUnicodeString 是字符串文字。尽管 ThisisNotUnicodeString 不是 unicode 文字,但哪种编码技术用于在内存中表示 ThisisNotUnicodeString?因为应该有一些编码技术来表示内存中的???? 字符。

2) 哪种编码技术用于在内存中表示 unicode 文字 a? UTF-8?如果是,如何知道占用的字节数?

3) 为什么c 没有在内存中表示,使用utf-16 技术?

【问题讨论】:

  • “内存表示”是什么意思?
  • 这可能不是在某些控制台中输入而是在具有指定编码的源文件中输入,然后您可以使用它。
  • a = u'a정정????' 是根据终端编码进行解码的。见sys.stdin.encoding。我们知道终端编码是 UTF-8,因为随后 b = unicode('a정정????', 'utf-8') 成功。 c = unicode('a정정????', 'utf-16') 因此失败,原因很明显,UTF-8 字节字符串不能被解码为 UTF-16。这两种编码完全不同。
  • unicode 的内部格式取决于构建。 Windows 和一些 Unix 系统上的 Python 2 使用内部类似于 UTF-16 的窄构建,但对于非 BMP 字符串会损坏,因为它将代理对计为字符串长度中的两个字符。大多数 Unix 系统使用宽版本,它将每个 Unicode 序数存储为一个 4 字节整数。
  • @eryksun 它从来不是 UTF-16。 UCS-2 或 UCS-4。

标签: python python-2.7 unicode


【解决方案1】:

使用哪种编码技术在内存中表示? utf-8?

您可以尝试以下方法:

ThisisNotUnicodeString.decode('utf-8')

如果得到结果,则为 UTF-8,否则不是。

如果要获取字符串的 UTF-16 表示,应先对其进行解码,然后使用 UTF-16 方案进行编码:

ThisisNotUnicodeString.decode('utf-8').encode('utf-16')

所以基本上,您可以将给定的字符串从/到 UTF-8/UTF-16 解码和编码,因为所有字符都可以在这两种方案中表示。

ThisisNotUnicodeString.decode('utf-8').encode('utf-16').decode('utf-16').encode('utf-8')

【讨论】:

  • 我有一个问题。如果我使用 utf-8 编码,那么我可以使用 latin-1 解码。你认为这是不可能的吗?根据您选择的代码点。因为 utf-8 向后兼容 latin-1 & ascii & cp-1252 & ...
【解决方案2】:

1) ThisisNotUnicodeString 是字符串文字。尽管 ThisisNotUnicodeString 不是 unicode 文字,但哪种编码技术用于在内存中表示 ThisisNotUnicodeString?因为应该有一些编码技术来表示内存中的정或?字符。

在交互式提示中,将使用哪种编码来编码 Python 2.X 的 str 类型取决于您的 shell 编码,例如,如果您在 Linux 系统下运行终端,终端的编码为 UTF-8 :

>>> s = "a정정?"
>>> s
'a\xec\xa0\x95\xec\xa0\x95\xf0\x9f\x92\x9b' 

现在尝试将终端窗口的编码更改为其他内容,在这种情况下,我已将 shell 的编码从 UTF-8 更改为 WINDOWS-1250:

 >>> s = "a???"

如果您在 tty 会话中尝试此操作,您会得到钻石而不是 ?至少在 Ubuntu 下你可能会得到不同的字符。

您可以得出结论,将使用哪种编码来确定交互式提示中str 的编码取决于shell。这适用于在 Python 解释器下交互运行的代码,非交互运行的代码会引发异常:

#main.py
s = "a정정?"

尝试运行代码引发SynatxError

$ python main.py
SyntaxError: Non-ASCII character '\xec' in file main.py...

这是因为 Python 2.X 默认使用 ASCII:

>>> sys.getdefaultencoding()
'ascii'

然后,您必须通过执行以下操作在代码中明确指定编码:

#main.py
#*-*encoding:utf-8*-*
s = "a정정?"

2) 使用哪种编码技术来表示内存中的 unicode 文字 a? UTF-8?如果是,如何知道占用的字节数?

请记住,如果您在不同的 shell 中运行代码,编码方案可能会有所不同,我已经在 Linux 下进行了测试,对于 Windows,这可能会略有不同,因此请查看您操作系统的文档。

要知道占用的字节数,使用len

>>> s = "a정정?"
>>> len(s)
11

s 正好占用 11 个字节。

2) 哪种编码技术用于在内存中表示 unicode 文字 a? UTF-8?如果是,如何知道占用的字节数?

嗯,这是一个混乱,unicode 类型没有编码。它只是一个 Unicode 字符点序列(也就是 Commercial At 的 U+0040)。

3) 为什么c没有在内存中表示,使用utf-16技术?

UTF-8 是一种不同于 UTF-16 的编码方案——UTF-8 表示的字符字节与 UTF-16 不同。这里:

>>> c = unicode('a정정?', 'utf-16')

你实际上是在这样做:

>>> "a정정?"
'a\xec\xa0\x95\xec\xa0\x95\xf0\x9f\x92\x9b'
>>> unicode('a\xec\xa0\x95\xec\xa0\x95\xf0\x9f\x92\x9b', 'utf-16')
UnicodeDecodeError: 'utf16' codec can't decode byte 0x9b in position 10: truncated data

这是因为您尝试解码 UTF-8 和 UTF-16。同样,两者都使用不同数量的字节来表示字符,它们只是两种不同的编码方案——以字节表示字符的不同方式。

供您参考: Python str vs unicode types

【讨论】:

  • 关于Unicode的内存表示问题,很多编程环境内部确实使用了UTF-8和UTF-16。问这个问题不一定是混乱的迹象。取决于字符串中字符的分布,各种表示在时间和空间上存在权衡。在内部,Python 3 尝试根据每个字符串中的最大序数值混合使用 UCS-1、UCS-2 和 UCS-4 来平衡这一点——并根据 API 请求缓存 UTF-8 和 UTF-16 编码.
  • “shell-dependent”应该是“console- or terminal-dependent”。 shell 只是另一个使用控制台或终端的程序。 Windows 用户通常不清楚这一点。许多人错误地认为 cmd.exe 是控制台。一般Unix用户的理解比较清楚。
  • @eryksun 没有看到上面的答案,让我说,在我的第三个问题(上面)中,失败的原因不太清楚。我对第三个问题的错误的理解是,在python2中,如果我说c = unicode('a정정?', 'utf-16'),那么,a정정?首先通过使用sys.stdin.encoding(在我的情况下是utf-8)编码存储在内存中,然后立即使用给出上述错误的utf-16 验证解码。对吗?
  • @overexchange,文字被读取为来自标准输入或源文件的已编码字节序列。例如,对于 UTF-8,字节的十进制值如下列表:[39, 97, 236, 160, 149, 236, 160, 149, 240, 159, 146, 155, 39],其中 39 是单引号的序号。它不是 u'' 文字,因此编译器使用此字节序列(不带引号)创建一个 str 对象。这个str 对象被传递给unicode 构造函数,它被告知将其解码为UTF-16,这是错误的编码,在这种情况下会失败,因为它不是偶数字节。
  • @eryksun 现在,我的问题是,如果我在abc.py 中说# coding = utf-8 并使用utf-8 源代码编码保存该文件(abc.py),那么,是否还不够在我的代码中使用s="a정정?" 而不是s = unicode("a정정?", 'utf-8')s = u'a정정?'?假设我对我的应用程序的 utf-8 编解码器感到满意。 &gt;&gt;&gt; s = 'a정정?' &gt;&gt;&gt; s.decode('utf-8') 工作正常
猜你喜欢
  • 1970-01-01
  • 2014-09-10
  • 2012-04-21
  • 2013-06-21
  • 2011-11-30
  • 2014-08-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多