如何迭代Python 3中的Unicode字符?
我需要一次一个字符地浏览一个Python字符串,但是一个简单的“for”循环会给我一个UTF-16代码单元:
str = "abcu20acU00010302U0010fffd"
for ch in str:
code = ord(ch)
print("U+{:04X}".format(code))
打印:
U+0061
U+0062
U+0063
U+20AC
U+D800
U+DF02
U+DBFF
U+DFFD
当我想要的是:
U+0061
U+0062
U+0063
U+20AC
U+10302
U+10FFFD
有没有什么办法可以让Python给我一系列的Unicode代码点,而不管字符串是如何在引擎盖下实际编码的? 我在这里测试Windows,但我需要能够在任何地方工作的代码。 它只需要在Python 3上工作,我不关心Python 2.x.
到目前为止我所能想到的最好的是:
import codecs
str = "abcu20acU00010302U0010fffd"
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也是“有种论点。”
在狭窄的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编码):
>>> s = "abcu20acU00010302U0010fffd"
>>> len(s)
8
>>> for c in s:
... print('U+{:04X}'.format(ord(c)))
...
U+0061
U+0062
U+0063
U+20AC
U+D800
U+DF02
U+DBFF
U+DFFD
解决方法:
>>> 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 = "abcu20acU00010302U0010fffd"
>>> 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
Python通常在内部将unicode值存储为UCS2。 UTF-32 U00010302字符的UTF-16表示是 UD800 UDF02,这就是您获得该结果的原因。
也就是说,有一些使用UCS4的python版本,但是这些版本并不相互兼容。
看看这里。
Py_UNICODE这种类型表示Python内部用作保存Unicode序号的基础的存储类型。 Python的默认构建对Py_UNICODE使用16位类型,并将Unicode值在内部存储为UCS2。 也可以构建一个UCS4版本的Python(最新的Linux发行版带有UCS4版本的Python)。 然后,这些构建对Py_UNICODE使用32位类型,并将Unicode数据内部存储为UCS4。 在wchar_t可用且与所选Python Unicode构建变体兼容的平台上,Py_UNICODE是wchar_t的typedef别名,以增强本机平台的兼容性。 在所有其他平台上,Py_UNICODE是unsigned short(UCS2)或unsigned long(UCS4)的typedef别名。
如果将该字符串创建为一个unicode对象,它应该能够自动一次中断一个字符。 例如:
Python 2.6:
s = u"abcu20acU00010302U0010fffd" # note u in front!
for c in s:
print "U+%04x" % ord(c)
我收到了:
U+0061
U+0062
U+0063
U+20ac
U+10302
U+10fffd
Python 3.2:
s = "abcu20acU00010302U0010fffd"
for c in s:
print ("U+%04x" % ord(c))
它为我工作:
U+0061
U+0062
U+0063
U+20ac
U+10302
U+10fffd
此外,我发现这个链接解释说,行为正常工作。 如果字符串来自文件等,它可能需要首先解码。
更新 :
我在这里找到了一个有见地的解释。 内部Unicode表示大小是一个编译时选项,如果在16位平面以外使用“宽”字符,则需要自行构建python以删除限制,或者使用此页面上的其中一种解决方法。 显然,很多Linux发行版都已经为我们做了这些,就像我上面遇到的一样。
链接地址: http://www.djcxy.com/p/54045.html