python解码部分utf-8字节数组

python解码部分utf-8字节数组,python,utf-8,Python,Utf 8,我正在从不知道UTF-8规则的通道获取数据。所以有时候,当UTF-8使用多个字节对一个字符进行编码时,我试图将部分接收到的数据转换为文本,在转换过程中会出现错误。由于接口的性质(没有任何结尾的流),我无法确定数据何时已满。因此,我需要处理部分utf-8解码。基本上,我需要解码我可以和存储部分数据。存储的部分数据将作为前缀添加到下一个数据中。我的问题是python中是否有一些简洁的函数允许它 [编辑] 只是为了让你们知道,我知道 但问题是它不会返回错误的位置,因此我不知道应该保留多少字节。到目前为

我正在从不知道UTF-8规则的通道获取数据。所以有时候,当UTF-8使用多个字节对一个字符进行编码时,我试图将部分接收到的数据转换为文本,在转换过程中会出现错误。由于接口的性质(没有任何结尾的流),我无法确定数据何时已满。因此,我需要处理部分utf-8解码。基本上,我需要解码我可以和存储部分数据。存储的部分数据将作为前缀添加到下一个数据中。我的问题是python中是否有一些简洁的函数允许它

[编辑] 只是为了让你们知道,我知道


但问题是它不会返回错误的位置,因此我不知道应该保留多少字节。

到目前为止,我提出了一个不太好的函数:

def decodeBytesUtf8Safe(toDec):
    """
    decodes byte array in utf8 to string. It can handle case when end of byte array is
    not complete thus making utf8 error. in such case text is translated only up to error.
    Rest of byte array (from error to end) is returned as second parameter and can be
    combined with next byte array and decoded next time.
    :param toDec: bytes array to be decoded a(eg bytes("abc","utf8"))
    :return:
     1. decoded string
     2. rest of byte array which could not be encoded due to error
    """
    okLen = len(toDec)
    outStr = ""
    while(okLen>0):
        try:
            outStr = toDec[:okLen].decode("utf-8")
        except UnicodeDecodeError as ex:
            okLen -= 1
        else:
            break
    return outStr,toDec[okLen:]
您可以使用以下脚本对其进行测试:

def test(arr):
    expStr = arr.decode("utf-8")
    errorCnt = 0
    for i in range(len(arr)+1):
        decodedTxt, rest = decodeBytesUtf8Safe(arr[0:i])
        decodedTxt2, rest2 = decodeBytesUtf8Safe(rest+arr[i:])
        recvString = decodedTxt+decodedTxt2
        sys.stdout.write("%02d ; %s (%s - %s )\n"%(i,recvString,decodedTxt, decodedTxt2))
        if(expStr != recvString):
            print("Error when divided at %i"%(i))
            errorCnt += 1
    return errorCnt

testUtf8 = bytes([0x61, 0xc5, 0xbd, 0x6c, 0x75, 0xc5, 0xa5, 0x6f, 0x75, 0xc4, 0x8d, 0x6b, 0xc3, 0xbd, 0x20, 0x6b, 0xc5, 0xaf, 0xc5, 0x88])
err = test(testUtf8)
print("total errors %i"%(err))
它将为您提供以下输出:

00 ; aŽluťoučký kůň ( - aŽluťoučký kůň )
01 ; aŽluťoučký kůň (a - Žluťoučký kůň )
02 ; aŽluťoučký kůň (a - Žluťoučký kůň )
03 ; aŽluťoučký kůň (aŽ - luťoučký kůň )
04 ; aŽluťoučký kůň (aŽl - uťoučký kůň )
05 ; aŽluťoučký kůň (aŽlu - ťoučký kůň )
06 ; aŽluťoučký kůň (aŽlu - ťoučký kůň )
07 ; aŽluťoučký kůň (aŽluť - oučký kůň )
08 ; aŽluťoučký kůň (aŽluťo - učký kůň )
09 ; aŽluťoučký kůň (aŽluťou - čký kůň )
10 ; aŽluťoučký kůň (aŽluťou - čký kůň )
11 ; aŽluťoučký kůň (aŽluťouč - ký kůň )
12 ; aŽluťoučký kůň (aŽluťoučk - ý kůň )
13 ; aŽluťoučký kůň (aŽluťoučk - ý kůň )
14 ; aŽluťoučký kůň (aŽluťoučký -  kůň )
15 ; aŽluťoučký kůň (aŽluťoučký  - kůň )
16 ; aŽluťoučký kůň (aŽluťoučký k - ůň )
17 ; aŽluťoučký kůň (aŽluťoučký k - ůň )
18 ; aŽluťoučký kůň (aŽluťoučký ků - ň )
19 ; aŽluťoučký kůň (aŽluťoučký ků - ň )
20 ; aŽluťoučký kůň (aŽluťoučký kůň -  )
total errors 0

您可以调用编解码器模块进行救援。它直接为您提供了一个增量解码器,完全满足您的需要:

import codecs

dec = codecs.getincrementaldecoder('utf8')()
您可以向它输入:
dec.decode(输入)
,当它结束时,可以选择添加一个
dec.decode(bytes(),True)
,强制它清除任何存储状态

测试变成:

>>> def test(arr):
    dec = codecs.getincrementaldecoder('utf8')()
    recvString = ""
    for i in range(len(arr)):
        recvString += dec.decode(arr[i:i+1])
        sys.stdout.write("%02d : %s\n" % (i, recvString))
    recvString += dec.decode(bytes(), True) # will choke on incomplete input...
    return recvString == arr.decode('utf8')

>>> testUtf8 = bytes([0x61, 0xc5, 0xbd, 0x6c, 0x75, 0xc5, 0xa5, 0x6f, 0x75, 0xc4, 0x8d, 0x6b, 0xc3, 0xbd, 0x20, 0x6b, 0xc5, 0xaf, 0xc5, 0x88])
>>> test(testUtf8)
00 : a
01 : a
02 : aŽ
03 : aŽl
04 : aŽlu
05 : aŽlu
06 : aŽluť
07 : aŽluťo
08 : aŽluťou
09 : aŽluťou
10 : aŽluťouč
11 : aŽluťoučk
12 : aŽluťoučk
13 : aŽluťoučký
14 : aŽluťoučký 
15 : aŽluťoučký k
16 : aŽluťoučký k
17 : aŽluťoučký ků
18 : aŽluťoučký ků
19 : aŽluťoučký kůň
True

这是你问题的解决方案还是你问题的一部分。如果这是你尝试过的,那应该在你的问题中。我尝试过。这似乎是可行的。但我对尺寸不满意。我觉得一些python大师可能会想出一些一行程序或者至少是一些可以在一个步骤中运行而不在循环中尝试的东西。。。所以这是一个有效的答案,它可能就在这里。我只想得到更好的答案:)试试看:你可能会得到更好的回答。祝你好运
>>> def test(arr):
    dec = codecs.getincrementaldecoder('utf8')()
    recvString = ""
    for i in range(len(arr)):
        recvString += dec.decode(arr[i:i+1])
        sys.stdout.write("%02d : %s\n" % (i, recvString))
    recvString += dec.decode(bytes(), True) # will choke on incomplete input...
    return recvString == arr.decode('utf8')

>>> testUtf8 = bytes([0x61, 0xc5, 0xbd, 0x6c, 0x75, 0xc5, 0xa5, 0x6f, 0x75, 0xc4, 0x8d, 0x6b, 0xc3, 0xbd, 0x20, 0x6b, 0xc5, 0xaf, 0xc5, 0x88])
>>> test(testUtf8)
00 : a
01 : a
02 : aŽ
03 : aŽl
04 : aŽlu
05 : aŽlu
06 : aŽluť
07 : aŽluťo
08 : aŽluťou
09 : aŽluťou
10 : aŽluťouč
11 : aŽluťoučk
12 : aŽluťoučk
13 : aŽluťoučký
14 : aŽluťoučký 
15 : aŽluťoučký k
16 : aŽluťoučký k
17 : aŽluťoučký ků
18 : aŽluťoučký ků
19 : aŽluťoučký kůň
True