Domanda

Dalla shell Python 2.6:

>>> import sys
>>> print sys.getdefaultencoding()
ascii
>>> print u'\xe9'
é
>>> 

mi aspettavo di avere sia un po 'senza senso o di un errore dopo l'istruzione di stampa, poiché il carattere "é" non fa parte del ASCII e non ho specificato una codifica. Credo di non capire quello che ASCII è l'impostazione predefinita mezzi codifica.

Modifica

I spostato la modifica alla le risposte e accettato come suggerito.

È stato utile?

Soluzione

Grazie a pezzi di varie risposte, penso che possiamo ricucire una spiegazione.

Per cercare di stampare una stringa unicode, u '\ xe9', Python implicitamente cercare di codificare la stringa utilizzando lo schema di codifica attualmente memorizzato in sys.stdout.encoding. Python in realtà riprende questa impostazione dall'ambiente che è stato avviato da. Se non riesce a trovare una codifica corretta dall'ambiente, solo allora lo fa tornare alla sua default , ASCII.

Per esempio, utilizzare una shell bash che codifica default UTF-8. Se inizio Python da esso, raccoglie e l'uso che l'impostazione:

$ python

>>> import sys
>>> print sys.stdout.encoding
UTF-8

Diamo per un attimo uscita shell Python e ambiente set di bash con qualche codifica falso:

$ export LC_CTYPE=klingon
# we should get some error message here, just ignore it.

Quindi riavviare il guscio pitone e verificare che effettivamente ripristinare la sua codifica predefinita ASCII.

$ python

>>> import sys
>>> print sys.stdout.encoding
ANSI_X3.4-1968

Bingo!

Se ora si tenta di uscita un po 'al di fuori del carattere Unicode ascii si dovrebbe ottenere un messaggio di errore bel

>>> print u'\xe9'
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' 
in position 0: ordinal not in range(128)

Consente uscita Python e scartare la shell bash.

Noi ora osservare ciò che accade dopo stringhe Python uscite. Per questo faremo prima iniziare una shell bash all'interno di un terminale grafico (io uso Gnome Terminal) e imposteremo il terminale di uscita decodificare con ISO 8859-1-alias latin-1 (terminali grafici di solito hanno la possibilità di Imposta codifica dei caratteri in una delle loro menu a discesa). Si noti che questo non cambia codifica l'attuale di ambiente shell, cambia solo il modo terminale stessa sarà decodificare uscita è dato, un po 'come un browser web fa. pertanto è possibile modificare la codifica del terminale, in modo indipendente dall'ambiente del guscio. Diamo quindi avviare Python dal guscio e verificare che sys.stdout.encoding è impostato per la codifica della shell (UTF-8 per me):

$ python

>>> import sys

>>> print sys.stdout.encoding
UTF-8

>>> print '\xe9' # (1)
é
>>> print u'\xe9' # (2)
é
>>> print u'\xe9'.encode('latin-1') # (3)
é
>>>

(1) emette pitone stringa binaria come è, terminale riceve e tenta di accoppiare il suo valore con latino-1 mappa dei caratteri. In latino-1, 0xE9 o 233 rese il carattere "E" e così è quello che il terminale visualizza.

(2) pitone tentativi di implicitamente codificare la stringa Unicode con qualsiasi schema è attualmente impostato in sys.stdout.encoding, in questo caso è di "UTF-8". Dopo codifica UTF-8, la stringa binaria risultante è '\ xc3 \ xA9' (vedi spiegazione più avanti). Terminale riceve il flusso come tale e cerca di decodificare 0xc3a9 usando latin-1, ma latin-1 va da 0 a 255 e così, decodifica soltanto flussi 1 byte alla volta. 0xc3a9 è di 2 byte lungo, latin-1 decoder dunque lo interpreta come 0xc3 (195) e 0xa9 (169) e che i rendimenti dei 2 personaggi:. A e ©

(3) python codifica unicode codice punto u '\ xe9' (233) con la 1-latin schema. Si scopre che i punti di codice latino-1 Range è 0-255 e punti per l'esatto stesso carattere Unicode all'interno di tale intervallo. Pertanto, Unicode punti di codice in tale intervallo produrranno lo stesso valore quando codificato in latino-1. Quindi u '\ xe9' (233) codificato in latin-1 produce anche la stringa binaria '\ xe9'. Terminale riceve tale valore e cerca di far corrispondere sul-1 latino mappa dei caratteri. Proprio come il caso (1), produce "e" e questo è ciò che viene visualizzato.

Diamo ora modificare le impostazioni del terminale di codifica UTF-8 dal menu a discesa (come si farebbe cambiare le impostazioni di codifica del browser web). Non c'è bisogno di smettere di Python o riavviare il guscio. codifica del terminale ora corrisponde Python. Proviamo a stampare di nuovo:

>>> print '\xe9' # (4)

>>> print u'\xe9' # (5)
é
>>> print u'\xe9'.encode('latin-1') # (6)

>>>

(4) pitone uscita un binario stringa come è. tentativi terminal per decodificare quel flusso con UTF-8. Ma UTF-8 non capisce il valore di 0xE9 (vedi spiegazione più avanti) ed è quindi in grado di convertirlo in un punto di codice Unicode. Nessun punto di codice trovato, nessun carattere stampato.

(5) pitone tentativi di implicitamente codificare la stringa Unicode con tutto ciò di in sys.stdout.encoding. Ancora "UTF-8". La stringa binaria risultante è '\ xc3 \ xA9'. r Terminaleceives il torrente e tenta di decodificare 0xc3a9 anche usando UTF-8. Si produce di nuovo 0xE9 valore del codice (233), che sulla mappa Unicode carattere punti al simbolo "E". terminale visualizza "E".

(6) python codifica stringa Unicode con latin-1, produce una stringa binaria con lo stesso valore '\ xe9'. Ancora una volta, per il terminale questo è praticamente uguale a caso (4).

Conclusioni: - Python uscite stringhe non Unicode come dati grezzi, senza considerare la sua codifica predefinita. Il terminale avviene solo per visualizzarli se codifica corrente corrisponde ai dati. - Python uscite stringhe Unicode dopo la codifica utilizzando lo schema indicato in sys.stdout.encoding. - Python ottiene tale impostazione dall'ambiente della shell. - il display terminale di uscita secondo le proprie impostazioni di codifica. -. Codifica del terminale è indipendente dal guscio del


Maggiori dettagli su unicode, UTF-8 e latin-1:

Unicode è fondamentalmente una tabella di caratteri dove alcuni tasti (punti di codice) sono stati convenzionalmente assegnati a punto alcuni simboli. per esempio. per convenzione è stato deciso che 0xE9 chiave (233) è il valore che punta al simbolo 'E'. ASCII e Unicode usano gli stessi punti di codice da 0 a 127, come fanno latin-1 e Unicode da 0 a 255. Cioè, 0x41 punti a 'A' in ASCII, latin-1 e Unicode, 0xC8 punti a 'U' in Latin-1 e Unicode, 0xE9 punti a 'e' in latino-1 e Unicode.

Quando si lavora con dispositivi elettronici, punti di codice Unicode bisogno di un modo efficiente per essere rappresentato elettronicamente. Questo è ciò che schemi di codifica sono circa. Esistono vari schemi di codifica Unicode (UTF7, UTF-8, UTF-16, UTF-32). L'approccio più intuitivo e diretto codificante avanti sarebbe usare semplicemente il valore di un punto di codice nella mappa Unicode come valore per la sua forma elettronica, ma Unicode ha attualmente oltre un milione di punti di codice, che significa che alcuni di essi richiedono 3 byte di essere espresso. Per lavorare in modo efficiente con il testo, un 1 a 1 mappatura sarebbe poco pratico, poiché richiederebbe che tutti i punti codice essere memorizzati nella esattamente la stessa quantità di spazio, con un minimo di 3 byte per carattere, indipendentemente dalla loro effettiva necessità.

La maggior parte degli schemi di codifica hanno carenze per quanto riguarda lo spazio necessario, quelli più economici non coprono tutti i punti di codice unicode, per esempio ascii copre solo il primo 128, mentre Latin-1 copre le prime 256. Altri che cercano di essere più completo finiscono anche essere uno spreco, poiché richiedono più byte del necessario, anche per comuni "economici" caratteri. UTF-16 per esempio, utilizza un minimo di 2 byte per carattere, comprese quelle nell'intervallo ASCII ( 'B' che è 65, richiede ancora 2 byte di archiviazione in UTF-16). UTF-32 è ancora più dispendioso in quanto memorizza tutti i caratteri in 4 byte.

UTF-8 accade aver abilmente risolto il dilemma, con uno schema in grado di punti di codice negozio con una quantità variabile di spazi byte. Come parte della sua strategia di codifica, punti di codice UTF-8 lacci con bit di flag che indicano (presumibilmente per decodificatori) le loro esigenze di spazio e loro confini.

UTF-8 codifica di punti di codice unicode nell'intervallo ASCII (0-127):

0xxx xxxx  (in binary)
  • le X mostrano lo spazio effettivo riservato a "memorizzare" il punto di codice durante la codifica
  • Lo 0 è un flag che indica al decodificatore UTF-8 che questo punto codice richiede solo 1 byte.
  • sulla codifica, UTF-8 non cambia il valore di punti di codice in tale intervallo specifico (cioè 65 codificato in UTF-8 è anche 65). Considerando che Unicode e ASCII sono compatibili anche nella stessa gamma, rende incidentalmente UTF-8 e ASCII compatibile anche in tale intervallo.

es. Unicode punto di codice per 'B' è '0x42' o 0100 0010 in formato binario (come abbiamo detto, è lo stesso in ASCII). Dopo la codifica in UTF-8 diventa:

0xxx xxxx  <-- UTF-8 encoding for Unicode code points 0 to 127
*100 0010  <-- Unicode code point 0x42
0100 0010  <-- UTF-8 encoded (exactly the same)

UTF-8 codifica di punti di codice Unicode sopra 127(Non-ASCII):

110x xxxx 10xx xxxx            <-- (from 128 to 2047)
1110 xxxx 10xx xxxx 10xx xxxx  <-- (from 2048 to 65535)
  • i bit iniziali '110' indicano al UTF-8 decodificatore l'inizio di un punto di codice codificato in 2 byte, mentre '1110' indica 3 byte, 11110 indicherebbe 4 byte e così via.
  • i '10' bit dei flag interni vengono utilizzati per segnalare l'inizio di un byte interno.
  • ancora una volta, il marchio della x lo spazio in cui il valore del punto di codice Unicode viene memorizzato dopo la codifica.

es. Punto 'é' codice Unicode è 0xE9 (233).

1110 1001    <-- 0xe9

Quando UTF-8 codifica questo valore, si determina che il valore è maggiore di 127 e meno di 2048, pertanto deve essere codificato in 2 byte:

110x xxxx 10xx xxxx   <-- UTF-8 encoding for Unicode 128-2047
***0 0011 **10 1001   <-- 0xe9
1100 0011 1010 1001   <-- 'é' after UTF-8 encoding
C    3    A    9

I 0xE9 punti di codice Unicode dopo UTF-8 codifica diventa 0xc3a9. Il che è esattamente come il terminale riceve. Se il terminale è impostato su stringhe di decodificare usando latin-1 (una delle codifiche non Unicode legacy), vedrete un ©, perché si dà il caso che 0xc3 in latino-1 punti a una e 0xa9 a ©.

Altri suggerimenti

Quando i caratteri Unicode vengono stampati sullo standard output, viene utilizzato sys.stdout.encoding. Un carattere non Unicode viene considerato in sys.stdout.encoding ed è solo inviato al terminale. Sul mio sistema (Python 2):

>>> import unicodedata as ud
>>> import sys
>>> sys.stdout.encoding
'cp437'
>>> ud.name(u'\xe9') # U+00E9 Unicode codepoint
'LATIN SMALL LETTER E WITH ACUTE'
>>> ud.name('\xe9'.decode('cp437')) 
'GREEK CAPITAL LETTER THETA'
>>> '\xe9'.decode('cp437') # byte E9 decoded using code page 437 is U+0398.
u'\u0398'
>>> ud.name(u'\u0398')
'GREEK CAPITAL LETTER THETA'
>>> print u'\xe9' # Unicode is encoded to CP437 correctly
é
>>> print '\xe9'  # Byte is just sent to terminal and assumed to be CP437.
Θ

sys.getdefaultencoding() viene utilizzato solo quando Python non ha un'altra opzione.

Si noti che Python 3.6 o successiva ignora codifiche su Windows e utilizza le API Unicode di scrivere Unicode al terminale. avvertenze No UnicodeEncodeError e il carattere corretto viene visualizzato se i supporti di carattere esso. Anche se il carattere non supporta i caratteri possono essere ancora cut-n-incollato dal terminale a un'applicazione di un carattere di sostegno e sarà corretto. Aggiornamento!

Il Python REPL cerca di raccogliere quello che codifica da utilizzare dal proprio ambiente. Se trova qualcosa sano di mente, allora tutto solo Works. E 'quando non può capire cosa sta succedendo che gli insetti fuori.

>>> print sys.stdout.encoding
UTF-8

sono specificato una codifica inserendo una stringa esplicita Unicode. Confrontare i risultati di non utilizzare il prefisso u.

>>> import sys
>>> sys.getdefaultencoding()
'ascii'
>>> '\xe9'
'\xe9'
>>> u'\xe9'
u'\xe9'
>>> print u'\xe9'
é
>>> print '\xe9'

>>> 

Nel caso di \xe9 poi Python assume la codifica di default (ASCII), la stampa così ... qualcosa di vuoto.

Si lavora per me:

import sys
stdin, stdout = sys.stdin, sys.stdout
reload(sys)
sys.stdin, sys.stdout = stdin, stdout
sys.setdefaultencoding('utf-8')

Come per Python default / implicita codifiche stringa e conversioni :

  • Quando printing unicode, è encoded con <file>.encoding.
    • quando il encoding non è impostato, il unicode è implicitamente convertito in str (dal momento che il codec di ciò è sys.getdefaultencoding(), cioè ascii, i caratteri nazionali causerebbe una UnicodeEncodeError)
    • per flussi standard, il encoding è dedotto da ambiente. E 'in genere impostato fot flussi tty (dai terminali di impostazioni internazionali), ma è probabile che non può essere impostato per tubi
      • così un print u'\xe9' buone probabilità di successo quando l'uscita è a un terminale, e non riuscire se è reindirizzato. Una soluzione è encode() la stringa con la codifica desiderata prima printing.
  • Quando printing str, i byte vengono inviati al flusso come è. Quali glifi gli spettacoli terminali dipenderà dalla sua impostazioni internazionali.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top