2015-12-01 21 views
6

Attualmente sto imparando Python e come sloveno uso spesso i caratteri UTF-8 per testare i miei programmi. Normalmente tutto funziona bene, ma c'è un problema che non riesco a superare. Anche se ho ottenuto la codifica dichiarato sulla parte superiore del file non riesce quando si tenta di invertire una stringa contenente caratteri specialiPython che inverte una stringa UTF-8

#-*- coding: utf-8 -*- 

a = "čšž" 
print a #prints čšž 
b = a[::-1] 
print b #prints �šō� instead of žšč 

C'è un modo per risolvere questo?

risposta

13

Python 2 stringhe sono stringhe di byte e il testo con codifica UTF-8 utilizza più byte per carattere. Solo perché il tuo terminale riesce a interpretare i byte UTF-8 come caratteri, non significa che Python sappia quali byte formano un carattere UTF-8.

tuo bytestring consiste di 6 byte, ogni due bytes forma un personaggio:

>>> a = "čšž" 
>>> a 
'\xc4\x8d\xc5\xa1\xc5\xbe' 

Tuttavia, il numero di byte UTF-8 usi dipende da dove nello standard Unicode è definito il carattere; I caratteri ASCII (i primi 128 caratteri nello standard Unicode) richiedono solo 1 byte ciascuno e molte emoji richiedono 4 byte!

In ordine UTF-8 è tutto; invertendo la bytestring sopra inverte i byte, risultando in alcuni incomprensibile quanto lo standard UTF-8 è interessato, ma la metà 4 byte solo capita essere valido UTF-8 sequenze (per š e ō):

>>> a[::-1] 
'\xbe\xc5\xa1\xc5\x8d\xc4' 
-----~~~~~~~~^^^^^^^^#### 
    |  š  ō  | 
    \     \ 
    invalid UTF8 byte opening UTF-8 byte missing a second byte 

Dovresti decodificare la stringa di byte su un oggetto unicode, che consiste di singoli caratteri. Inversione quell'oggetto ti dà i risultati giusti:

b = a.decode('utf8')[::-1] 
print b 

Si può sempre codificare retro per UTF-8 di nuovo oggetto:

b = a.decode('utf8')[::-1].encode('utf8') 

Si noti che in Unicode, è ancora possibile incorrere in problemi quando inversione di testo, quando vengono utilizzati combining characters. Inversione testo con caratteri che conciliano la pone coloro che unisce personaggi di fronte, piuttosto che dopo il carattere si combinano con, in modo che ti combinano con il carattere sbagliato invece:

>>> print u'e\u0301a' 
éa 
>>> print u'e\u0301a'[::-1] 
áe 

È per lo più possibile evitare questo convertendo i dati Unicode per la sua forma normalizzata (che sostituisce le combinazioni con i moduli 1-codepoint) ma ci sono molti altri caratteri Unicode esotici che non giocano bene con le inversioni di stringhe.

+0

Giusto per chiarire: _ "ma ci sono molti altri caratteri esotici Unicode che non interagiscono con inversioni di stringhe" _ means _ "non funzionano bene con inversioni di stringhe" _ o _ "non sono influenzate da inversioni di stringhe "_? – Piovezan

+0

@Piovezan: Non sono sicuro al 100% me stesso; Sto andando con * non giocare bene con le inversioni di stringhe *. –

Problemi correlati