如何在Python中确定UTF-8编码字符串的字节长度?

27

我正在处理Amazon S3上传,并且遇到了键名过长的问题。S3限制键名长度以字节为单位,而非字符。

来自文档的说明:

键名是一个Unicode字符序列,其UTF-8编码最多为1024个字节。

我还尝试在文件名中嵌入元数据,因此需要能够使用Python计算字符串的当前字节长度,以确保元数据不会使键名过长(在这种情况下,我将不得不使用单独的元数据文件)。

如何确定utf-8编码字符串的字节长度?再次强调,我不关心字符长度…而是用于存储字符串的实际字节长度。

3个回答

41
def utf8len(s):
    return len(s.encode('utf-8'))

在Python 2和3中都运行良好。


1
谢谢。我还发现了一个网站,它展示了如何在几种语言中实现它:http://rosettacode.org/wiki/String_length#Byte_Length_49 - user319862

12
使用字符串的'encode'方法将字符字符串转换为字节字符串,然后像平常一样使用len()函数:
>>> s = u"¡Hola, mundo!"                                                      
>>> len(s)                                                                    
13 # characters                                                                             
>>> len(s.encode('utf-8'))   
14 # bytes

6
请不要将str作为变量名!这将导致许多问题。 - Mark Ransom

8

把字符串进行编码并在结果上使用 len 命令非常好用,正如其他答案所示。但是需要注意的是,它确实需要先建立一个临时拷贝字符串——如果你正在处理非常大的字符串,这可能不是最优解(虽然我认为 1024 字节并不算 )。UTF-8 结构允许你非常容易地获取每个字符的长度,甚至不需要编码,尽管编码单个字符可能更容易。我这里同时介绍了两种方法,它们应该得出相同的结果。

def utf8_char_len_1(c):
    codepoint = ord(c)
    if codepoint <= 0x7f:
        return 1
    if codepoint <= 0x7ff:
        return 2
    if codepoint <= 0xffff:
        return 3
    if codepoint <= 0x10ffff:
        return 4
    raise ValueError('Invalid Unicode character: ' + hex(codepoint))

def utf8_char_len_2(c):
    return len(c.encode('utf-8'))

utf8_char_len = utf8_char_len_1

def utf8len(s):
    return sum(utf8_char_len(c) for c in s)

3
请注意,为了避免复制,这个操作所需的时间大约比 len(s.encode('utf-8')) 多180倍,至少在我的Python 3.3.2上,对于一个包含1000个UTF8字符的字符串从这里生成。(如果你用C语言编写相同的算法,速度应该是相当的。) - Danica
@Dougal,感谢您运行测试。这是有用的信息,对于评估可能的解决方案至关重要。我有一种感觉它可能会慢一些,但不知道具体程度。您尝试过两个版本吗? - Mark Ransom
1
带有utf8_char_len_2版本的速度比utf8_char_len_1慢大约1.5倍。当然,我们在每种情况下都只谈论不到一毫秒的时间,所以如果你只是偶尔这样做,那就无关紧要:2微秒/375微秒/600微秒。话虽如此,复制1kb的内存也不太可能有影响。 :) - Danica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接