2017-10-21 132 views
0

這可能是一個微型優化,但我想檢查給定字節流是否有效UTF-8,因爲它通過我的應用程序,但我不想保留結果解碼的代碼點。換句話說,如果我打電話給large_string.decode('utf-8'),假設編碼成功了,我不希望保留通過解碼返回的Unicode字符串,並且不希望浪費內存。驗證一個字節流是否有效UTF-8(或其他編碼)沒有複製

有幾種方法可以做到這一點,例如一次讀取幾個字節,嘗試decode(),然後追加更多字節,直到decode()成功(或者我已經用盡了單個字符的最大字節數編碼)。但ISTM應該可以使用現有的解碼器,這樣就可以簡單地丟棄已解碼的unicode字符,而不必自己推出解碼器。但是沒有什麼可以立即想到刷新stdlib文檔。

+0

您是否可以將長字符串/流分割爲「塊」,以確保不會在一對字符之間劃分有效的多字節trf8編碼字符? – martineau

回答

2

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

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

這是一個IncrementalDecoder() instance。然後可以供給該解碼器的數據爲了和驗證流:

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

解碼器返回數據解碼到目前爲止(減去局部多字節序列,那些保持爲狀態你解碼下一個時間大塊)。那些較小的字符串創建和丟棄很便宜,你不會在這裏創建一個大字符串。

由於UTF-8是一種使用可變字節數的格式,因此您無法提供上述循環部分數據。部分塊在開始時很可能具有無效數據。

如果您不能從頭開始驗證,那麼您的第一個塊可能是最多可以有三個連續字節。您可以只是刪除那些第一:

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

現在,UTF-8是足夠的結構,所以你也完全是用Python代碼中使用更多這樣的二進制測試驗證流,但你根本不打算匹配內置解碼器可以解碼的速度。

+0

'utf8_decoder.decode(chunk)'解碼並返回結果解碼對象(代碼忽略)。如何比僅僅使用'string.decode('utf-8')'並且忽略它的返回值(當然在'try/except'內)更好? – martineau

+0

@martineau:因爲這可以讓你傳遞部分數據,一路拋棄結果。解碼器擁有足夠的狀態來處理下一個分塊,等等。 –

+0

@martineau:所以部分解碼是*更小*。 –

相關問題