2013-09-07 24 views
6

W Pythonie 2.7 mogę pomyślnie konwertować ciąg znaków Unicode "abc\udc34xyz" na UTF-8 (wynikiem jest "abc\xed\xb0\xb4xyz"). Ale kiedy przekazuję ciąg znaków UTF-8 do np. pango_parse_markup() lub g_convert_with_fallback(), pojawia się komunikat "Nieprawidłowa kolejność bajtów w danych wejściowych konwersji". Najwyraźniej funkcje GTK/Pango wykrywają "niepowiązany surogat" w łańcuchu i (poprawnie?) Odrzucają go.wykryj/usuń niepowiązany znak zastępczy w Pythonie 2 + GTK

Python 3 nie zezwala nawet na konwersję ciągu znaków Unicode na kodowanie UTF-8 (błąd: kodek '' utf-8 'nie może kodować znaku' \ udc34 'w pozycji 3: surrogaty nie są dozwolone "), ale Mogę uruchomić "abc\udc34xyz".encode("utf8", "replace"), aby uzyskać poprawny ciąg znaków UTF8 z samotnym surogatem zastąpionym przez inną postać. Dla mnie to w porządku, ale potrzebuję rozwiązania dla Pythona 2.

Pytanie brzmi: w Pythonie 2.7, jak mogę przekonwertować ten ciąg Unicode na UTF-8, zastępując samotnego surogata jakimś zastępczym znakiem, takim jak U + FFFD? Najlepiej używać tylko standardowych funkcji Pythona i funkcji GTK/GLib/G ...

Przy okazji. Iconv może konwertować ciąg znaków na UTF8, ale po prostu usuwa zły znak zamiast zastępowania go U + FFFD.

Odpowiedz

9

Można to zrobić samemu zamienniki przed kodowaniem:

import re 

lone = re.compile(
    ur'''(?x)   # verbose expression (allows comments) 
    (     # begin group 
    [\ud800-\udbff]  # match leading surrogate 
    (?![\udc00-\udfff]) # but only if not followed by trailing surrogate 
    )     # end group 
    |     # OR 
    (     # begin group 
    (?<![\ud800-\udbff]) # if not preceded by leading surrogate 
    [\udc00-\udfff]  # match trailing surrogate 
    )     # end group 
    ''') 

u = u'abc\ud834\ud82a\udfcdxyz' 
print repr(u) 
b = lone.sub(ur'\ufffd',u).encode('utf8') 
print repr(b) 
print repr(b.decode('utf8')) 

wyjściowa:

u'abc\ud834\U0001abcdxyz' 
'abc\xef\xbf\xbd\xf0\x9a\xaf\x8dxyz' 
u'abc\ufffd\U0001abcdxyz' 
-1

Oto co ustalony ten problem dla mnie:

invalid_string.encode('utf16').decode('utf16', 'replace')

mi się, że pary zastępcze są częścią UTF-16, i dlatego enc oding/decoding z UTF-8 nic nie robi.