字符串长度不等于字节数:用Python检查UTF-8文本大小

举报
yd_283252214 发表于 2026/10/21 11:53:12 2026/10/21
【摘要】 用6组本地验证样例区分Python字符串码点数与UTF-8字节数,并说明换行、BOM、JSON序列化和Unicode规范化的统计边界。

在给接口字段做大小检查、记录日志或估算文本体积时,常见的问题是把“字符串长度”直接当作“字节数”。同样是一段可读文本,采用不同编码、是否包含换行、是否先转成JSON,都会影响最终字节序列。本文只解决一个小问题:已知Python字符串,如何计算它按UTF-8编码后的长度。

先明确统计对象

Python 3的str表示Unicode文本,len(text)统计Unicode码点的数量;text.encode("utf-8")返回bytes,再对它调用len,才是这次UTF-8编码结果的字节数。码点数也不一定等于人眼看到的字形数量,因此不要把这两个值都笼统叫作“字数”。

例如,ASCII文本abc有3个码点、3字节;“云”有1个码点、3字节;😀有1个码点、4字节。不能用“中文总是几个字符”之类的粗略倍数替代实际编码。

一个可以直接运行的检查

samples = [
    ("", 0),
    ("abc", 3),
    ("云", 3),
    ("😀", 4),
    ("a\nb", 3),
    ("云服务器", 12),
]

for text, expected in samples:
    data = text.encode("utf-8")
    assert len(data) == expected
    print(ascii(text), "code_points=", len(text), "utf8_bytes=", len(data))

以上六组输入已在本地运行检查。UTF-8字节数依次为0、3、3、4、3、12。使用ascii(text)打印样例,是为了让换行、中文和emoji都能以转义形式显示,减少终端自身输出编码带来的干扰;它只影响展示,不改变被测text。

这段代码没有统计什么

这里算的是当前字符串编码后的裸字节数,不包含文件的BOM、HTTP请求头、TLS开销,也不代表压缩后的网络流量。如果实际要发送JSON,应先按真实序列化方式生成请求体,再统计最终字节;不要用某个字段的长度代替整个请求的长度。

换行也属于内容:"a\nb"中的换行是一个LF,编码后合计3字节;如果原文件使用CRLF,结果会不同。读取文本时可能发生换行转换,因此需要确认原文件真实大小时,应检查文件本身的字节,而不是把读出的文本重新编码后假定两者相等。

外观看起来相同,也可能不同

é可以由单一码点表示,也可以由e和组合重音两个码点表示;它们按UTF-8编码分别是2字节和3字节。本例按原输入计算,不自动做Unicode规范化。业务是否要规范化,应由字段协议决定,不能为了减少大小而擅自改写用户内容。

实际使用时,先确定协议使用的编码和限制单位,再对最终待写入或待发送的内容进行检查。本文没有调用云资源或发送网络请求,仅演示本地文本编码。

参考:Python官方文档《Unicode HOWTO》,https://docs.python.org/3/howto/unicode.html 。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。