[Python-de] utf8 Problem mit Blockgrenzen

"Martin v. Löwis" martin at v.loewis.de
Sam Aug 20 14:20:11 CEST 2005


Hans-Peter Jansen wrote:
> So, wie die Sache steht, bleibt mir wohl nix anderes übrig, als auf 
> zeilenweise Verarbeitung auszuweichen, oder hat jemand eine bessere 
> Idee?

In Python 2.4 kann der UTF-8-Decoder einen "partial mode":

decoded = codecs.utf_8_decode(encoded, "strict", 0)

Der letzte Parameter gibt an, ob es sich um das Ende der Eingabe
handelt. Falls nicht, und falls am Ende Bytes fehlen, gibt er
nur die dekodierten Zeichen und die Zahl der dazu konsumierten
Bytes an.

Man kann also schreiben

   rest = ''
   while True:
     data = self.a2psfile.read(BUFSIZE)
     if not data:
         pfp.write(rest.decode("utf-8").encode("cp850"))
         break
     decoded, len = codecs.utf_8_decode(rest + data, "strict", 0)
     rest = data[len:]
     pfp.write(decoded.encode("cp850"))

In älteren Python-Versionen kann man das ineffizient nachbilden:

def utf_8_decode(data, errors, final):
    if final:
        return data.decode("utf-8", errors), len(data)
    last = ord(data[-1])
    if last < 0x80:
        # ASCII, always single-byte
        return data.decode("utf-8", errors), len(data)
    if last >= 0xc0:
        # last byte is lead byte
        return data[:-1].decode("utf-8", errors), len(data)-1
    # find lead byte
    i = -2
    while ord(data[i]) < 0xc0: i++
    last = ord(data[i])
    incomplete = False
    if last < 0xe0:
       # one extra byte, cannot be incomplete here
       pass
    elif last < 0xf0:
       # two extra bytes, incomplete if we have only one
       incomplete = (i != -3)
    else:
       # three extra bytes
       incomplete = (i != -4)
    if incomplete:
       return data[:i].decode("utf-8", errors), len(data)+i
    return data.decode("utf-8", errors)

Achtung: Dieser Code ist komplett ungetestet.

Ciao,
Martin