2009-09-24 14 views
16

Supponiamo per un momento che non sia possibile utilizzare print (e quindi godere del beneficio del rilevamento automatico della codifica). Quindi questo ci lascia con sys.stdout. Tuttavia, sys.stdout è così stupido da not do any sensible encoding.Scrittura stringhe unicode tramite sys.stdout in Python

Ora si legge la pagina wiki di Python PrintFails e va a provare il seguente codice:

$ python -c 'import sys, codecs, locale; print str(sys.stdout.encoding); \ 
    sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout); 

Tuttavia anche questo non funziona (almeno su Mac). Troppo vedere perché:

>>> import locale 
>>> locale.getpreferredencoding() 
'mac-roman' 
>>> sys.stdout.encoding 
'UTF-8' 

(UTF-8 è ciò che il proprio terminale capisce).

Così si cambia il codice precedente:

$ python -c 'import sys, codecs, locale; print str(sys.stdout.encoding); \ 
    sys.stdout = codecs.getwriter(sys.stdout.encoding)(sys.stdout); 

E ora stringhe Unicode vengono inviati correttamente sys.stdout e quindi stampati correttamente sul terminale (sys.stdout è attaccato al terminale).

È questo il modo corretto di scrivere stringhe unicode in sys.stdout o dovrei fare qualcos'altro?

EDIT: a volte - per esempio, quando pipe l'output less - sys.stdout.encoding sarà None. in questo caso, il codice sopra non funzionerà.

+0

s/my/one's/for consistency – icedwater

risposta

3

Non è chiaro per il mio motivo per cui non si sarebbe in grado di stampare; ma supponendo che sì, l'approccio mi sembra giusto.

+1

Una ragione per cui non posso usare 'print' è per evitare quello spazio' print' print. Guarda l'uso di 'sys.stdout' qui: http://stackoverflow.com/questions/1396820/apt-like-column-output-python-library/1397382#1397382 –

+3

Potresti costruire linee complete e poi stampare loro. –

+0

Bravo! Sì, in quel caso posso usare 'print' –

10

La migliore idea è verificare se si è connessi direttamente a un terminale. Se lo sei, usa la codifica del terminale. Altrimenti, utilizza la codifica preferita del sistema.

if sys.stdout.isatty(): 
    default_encoding = sys.stdout.encoding 
else: 
    default_encoding = locale.getpreferredencoding() 

È anche molto importante consentire sempre all'utente di specificare la codifica desiderata. Di solito ne faccio una opzione da riga di comando (come -e ENCODING) e la analizzo con il modulo optparse.

Un'altra cosa buona è non sovrascrivere sys.stdout con un codificatore automatico. Crea il tuo codificatore e usalo, ma lascia solo sys.stdout. È possibile importare librerie di terze parti che scrivono codifiche dirette direttamente su sys.stdout.

8

C'è una variabile di ambiente opzionale "PYTHONIOENCODING" che può essere impostata su una codifica predefinita desiderata. Sarebbe un modo per afferrare la codifica desiderata dall'utente in un modo coerente con tutto il Python. È sepolto nel manuale Python here.

27
export PYTHONIOENCODING=utf-8 

farà il lavoro, ma non è possibile impostarlo su python stesso ...

quello che possiamo fare è verificare se non è tramontando e dire all'utente di impostare prima sceneggiatura chiamata con:

if __name__ == '__main__': 
    if (sys.stdout.encoding is None): 
     print >> sys.stderr, "please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout." 
     exit(1) 
+0

Grazie mille, lavora per me. – Kino

6

Questo è quello che sto facendo nella mia domanda:

sys.stdout.write(s.encode('utf-8'))

questo è l'esatto contrario correzione per la lettura dei nomi UTF-8 da argv:

for file in sys.argv[1:]: 
    file = file.decode('utf-8') 

Questo è molto brutto (IMHO) in quanto ti costringe a lavorare con UTF-8 .. che è la norma su Linux/Mac, ma non su Windows ... Funziona comunque per me :)

Problemi correlati