【发布时间】:2011-08-27 23:01:09
【问题描述】:
我想在不破坏任何字符的情况下将u"an arbitrary unicode string" 拆分为 300 个字节的块。字符串将被写入使用unicode_string.encode("utf8") 的需要utf8 的套接字。我不想破坏任何角色。我该怎么做?
【问题讨论】:
我想在不破坏任何字符的情况下将u"an arbitrary unicode string" 拆分为 300 个字节的块。字符串将被写入使用unicode_string.encode("utf8") 的需要utf8 的套接字。我不想破坏任何角色。我该怎么做?
【问题讨论】:
如果您可以确保您的字符的 utf-8 表示只有 2 个字节长,那么您应该可以安全地将 unicode 字符串拆分为 150 个字符的块(对于大多数欧洲编码来说,这应该是正确的)。但是 utf-8 是可变宽度编码。因此可能会将 unicode 字符串拆分为单个字符,将每个 char 转换为 utf-8 并填充缓冲区,直到达到最大块大小...如果必须高吞吐量,这可能效率低下并且是个问题...
【讨论】:
UTF-8 有一个特殊属性,即所有连续字符都是0x80–0xBF(从第 10 位开始)。所以只要确保你没有在一个之前分裂。
类似的东西:
def split_utf8(s, n):
if len(s) <= n:
return s, None
while ord(s[n]) >= 0x80 and ord(s[n]) < 0xc0:
n -= 1
return s[0:n], s[n:]
应该可以解决问题。
注意:它是在编码值上完成的,即python 2中的str和python 3中的bytes。python 3 bytes.__getitem__还包括对ord的调用,所以只需放弃它在那里。
【讨论】:
len(s) 为您提供字符串中的 Unicode 字符数,而 n 是所需的 UTF-8 字节数。
.encode() 之后调用,len(bytes) 返回字节数(在答案中添加了注释以明确这一点)。
bytes 传递到函数中,因为 s[n] 然后返回一个 int ord 无法处理。
ord 将字符或字节转换为整数,而您已经有整数,只需删除ord。
UTF-8 就是为此而设计的。
def split_utf8(s, n):
"""Split UTF-8 s into chunks of maximum length n."""
while len(s) > n:
k = n
while (ord(s[k]) & 0xc0) == 0x80:
k -= 1
yield s[:k]
s = s[k:]
yield s
未测试。但是你找到一个分割的地方,然后原路返回,直到你到达一个字符的开头。
但是,如果用户可能想要查看单个块,您可能希望改为在字素簇边界上进行拆分。这要复杂得多,但并非难以处理。例如,在"é" 中,您可能不想拆分"e" 和"´"。或者你可能不在乎,只要他们最终再次粘在一起。
【讨论】:
(ord(s[k]) & 0xc0) == 0x80 和 "\x80" <= s[k] <= "\xBF" 一样吗?我确实觉得这个做工精巧
使用设计为每个字符固定长度的 unicode 编码,例如utf-32:
>>> u_32 = u'Юникод'.encode('utf-32')
>>> u_32
'\xff\xfe\x00\x00.\x04\x00\x00=\x04\x00\x008\x04\x00\x00:\x04\x00\x00>\x04\x00\x
004\x04\x00\x00'
>>> len(u_32)
28
>>> len(u_32)%4
0
>>>
编码后,您可以发送任意大小的块(大小必须是 4 字节的倍数)而不会破坏字符
【讨论】:
经过测试。
def split_utf8(s , n):
assert n >= 4
start = 0
lens = len(s)
while start < lens:
if lens - start <= n:
yield s[start:]
return # StopIteration
end = start + n
while '\x80' <= s[end] <= '\xBF':
end -= 1
assert end > start
yield s[start:end]
start = end
【讨论】: