Skip to main content
 首页 » 编程设计

python之验证字节流是否为有效的 UTF-8(或其他编码),无需复制

2025年05月04日22mayingbao

这可能是一个微优化,但我想检查给定字节流在通过我的应用程序时是否是有效的 UTF-8,但我不想保留结果解码代码点。换句话说,如果我要调用 large_string.decode('utf-8'),假设编码成功,我不想保留解码返回的 unicode 字符串,并且不想浪费内存在上面。

有多种方法可以做到这一点,例如一次读取几个字节,尝试decode(),然后附加更多字节直到decode()成功(或者我已经用尽了编码中单个字符的最大字节数)。但是 ISTM 应该可以以一种简单地丢弃解码的 unicode 字符而不必自己滚动的方式使用现有的解码器。但是搜索 stdlib 文档时,什么也没有立即浮现在脑海中。

请您参考如下方法:

您可以使用 codecs module 提供的增量解码器:

utf8_decoder = codecs.getincrementaldecoder('utf8')() 

这是一个 IncrementalDecoder() instance .然后,您可以按顺序提供此解码器数据并验证流:

# for each partial chunk of data: 
    try: 
        utf8_decoder.decode(chunk) 
    except UnicodeDecodeError: 
        # invalid data 

解码器返回到目前为止解码的数据(减去部分多字节序列,这些序列在下次解码 block 时保持为状态)。这些较小的字符串创建和丢弃的成本很低,您不会在此处创建大字符串。

您不能提供上述循环部分数据,因为 UTF-8 是一种使用可变字节数的格式;部分块在开始时可能有无效数据。

如果您无法从头开始验证,那么您的第一个 block 可能以最多三个连续字节开始。您可以先删除那些:

first_chunk = b'....' 
for _ in range(3): 
    if first_chunk[0] & 0xc0 == 0x80: 
        # remove continuation byte 
        first_chunk = first_chunk[1:] 

现在,UTF-8 的结构足够了,因此您还可以使用更多此类二进制测试完全在 Python 代码中验证流,但您根本无法匹配内置解码器的解码速度。