[Python-de] utf8 Problem mit Blockgrenzen

Hans-Peter Jansen hpj at urpla.net
Sam Aug 20 15:08:42 CEST 2005


Am Samstag, 20. August 2005 14:20 schrieb Martin v. Löwis:
> 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"))

Genau an sowas dachte ich, als ich mit dem Problem konfrontiert war. Gut 
zu wissen, auch wenn es erstmal nur für 2.4 geht.

> 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.

..und viel zu komplex, um in meinem Falle einen Einsatz zu 
rechtfertigen. Aber dennoch sehr nützlich, um mehr über die Struktur 
der utf8 Kodierung zu erfahren. So komprimiert habe ich das noch 
nirgends gefunden. Cool, danke Martin.

Das lege heute nacht unter mein Kopfkissen ;-)

Pete