如何在python3中迭代Unicode字符?

2024-09-30 10:37:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要一次一个字符地遍历一个Python字符串,但是一个简单的“for”循环给出了UTF-16代码单元:

str = "abc\u20ac\U00010302\U0010fffd"
for ch in str:
    code = ord(ch)
    print("U+{:04X}".format(code))

打印出:

^{pr2}$

当我想要的是:

U+0061
U+0062
U+0063
U+20AC
U+10302
U+10FFFD

有没有办法让Python给出Unicode代码点的序列,而不管字符串实际上是如何编码的?我在这里测试Windows,但是我需要在任何地方都能工作的代码。它只需要在Python3上运行,我不关心Python2.x

到目前为止,我所能想到的最好的是:

import codecs
str = "abc\u20ac\U00010302\U0010fffd"
bytestr, _ = codecs.getencoder("utf_32_be")(str)
for i in range(0, len(bytestr), 4):
    code = 0
    for b in bytestr[i:i + 4]:
        code = (code << 8) + b
    print("U+{:04X}".format(code))

但我希望有更简单的方法。在

(对于精确的Unicode术语,学究式的吹毛求疵会被一条线索狠狠地揍了一顿。我想我已经清楚地表明了我的目标,请不要用“但是UTF-16在技术上也是Unicode”之类的论点浪费空间。)


Tags: 字符串代码inforunicodecodechutf
3条回答

Python通常在内部将unicode值存储为UCS2。UTF-32\U00010302字符的UTF-16表示是\UD800\UDF02,这就是您得到这个结果的原因。在

也就是说,有些python构建使用UCS4,但是这些构建彼此不兼容。在

看看here。在

Py_UNICODE This type represents the storage type which is used by Python internally as basis for holding Unicode ordinals. Python’s default builds use a 16-bit type for Py_UNICODE and store Unicode values internally as UCS2. It is also possible to build a UCS4 version of Python (most recent Linux distributions come with UCS4 builds of Python). These builds then use a 32-bit type for Py_UNICODE and store Unicode data internally as UCS4. On platforms where wchar_t is available and compatible with the chosen Python Unicode build variant, Py_UNICODE is a typedef alias for wchar_t to enhance native platform compatibility. On all other platforms, Py_UNICODE is a typedef alias for either unsigned short (UCS2) or unsigned long (UCS4).

在使用窄Unicode内部版本的Python 3.2.1上:

PythonWin 3.2.1 (default, Jul 10 2011, 21:51:15) [MSC v.1500 32 bit (Intel)] on win32.
Portions Copyright 1994-2008 Mark Hammond - see 'Help/About PythonWin' for further copyright information.
>>> import sys
>>> sys.maxunicode
65535

您发现了什么(UTF-16编码):

^{pr2}$

绕道而行:

>>> import struct
>>> s=s.encode('utf-32-be')
>>> struct.unpack('>{}L'.format(len(s)//4),s)
(97, 98, 99, 8364, 66306, 1114109)
>>> for i in struct.unpack('>{}L'.format(len(s)//4),s):
...     print('U+{:04X}'.format(i))
...     
U+0061
U+0062
U+0063
U+20AC
U+10302
U+10FFFD

Python 3.3更新:

现在它的工作方式与OP期望的一样:

>>> s = "abc\u20ac\U00010302\U0010fffd"
>>> len(s)
6
>>> for c in s:
...     print('U+{:04X}'.format(ord(c)))
...     
U+0061
U+0062
U+0063
U+20AC
U+10302
U+10FFFD

如果将字符串创建为unicode对象,它应该能够一次自动断开一个字符。E、 g.:

Python2.6:

s = u"abc\u20ac\U00010302\U0010fffd"   # note u in front!
for c in s:
    print "U+%04x" % ord(c)

我收到了:

^{pr2}$

Python3.2:

s = "abc\u20ac\U00010302\U0010fffd"
for c in s:
    print ("U+%04x" % ord(c))

它对我有用:

^{pr2}$

另外,我发现了this link,它解释了行为是正确工作的。如果字符串来自文件等,则可能需要先对其进行解码。在

更新

我发现了一个很有见地的explanation here。内部Unicode表示大小是一个编译时选项,如果在16位平面之外使用“宽”字符,则需要自己构建python来消除限制,或者使用本页中的一种解决方法。显然,正如我在上面遇到的那样,许多Linux发行版已经为您做了这项工作。在

相关问题 更多 >

    热门问题