验证字节流是否为有效的UTF-8(或其他编码)而不带副本

Igu*_*aut 1 python character-encoding

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

我可以通过多种方式来执行此操作,例如一次读取几个字节,尝试读取decode(),然后追加更多字节直到decode()成功(否则,我已经用完了编码中单个字符的最大字节数)。但是,在ISTM中,应该有可能以一种简单的方式丢弃现有的Unicode字符,而不必自己动手使用现有的解码器。但是搜索stdlib文档没有立即想到的事情。

Mar*_*ers 5

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

utf8_decoder = codecs.getincrementaldecoder('utf8')()
Run Code Online (Sandbox Code Playgroud)

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

# for each partial chunk of data:
    try:
        utf8_decoder.decode(chunk)
    except UnicodeDecodeError:
        # invalid data
Run Code Online (Sandbox Code Playgroud)

解码器返回到目前为止已解码的数据(减去部分多字节序列,这些序列将在下一次解码块时保留为状态)。那些较小的字符串创建和丢弃都很便宜,这里您不是在创建较大的字符串。

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

如果您不能从头开始验证,那么您的第一个块可能以最多三个连续字节开始。您可以先删除它们:

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

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