2013-07-02 11 views
7

Mam skrypt Python, który zapisuje niektóre ciągi z kodowaniem UTF-8. W moim skrypcie używam głównie funkcji str() do rzutowania na ciąg. Wygląda to tak:Opis Python Unicode i Linux terminal

mystring="this is unicode string:"+japanesevalues[1] 
#japanesevalues is a list of unicode values, I am sure it is unicode 
print mystring 

Nie używam terminala Python, tylko standardowy terminal Linux Red Hat x86_64. Ustawiłem terminal na wyjście z utf8 chars.

Jeśli mogę wykonać to:

#python myscript.py 
this is unicode string: カラダーズ ソフィー 

Ale jeśli to zrobić:

#python myscript.py > output 

mam typowy błąd:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 253-254: ordinal not in range(128) 

Dlaczego tak jest?

+0

W swoim pytaniu powiedziałeś, że "niektóre ciągi z kodowaniem UTF-8", w jaki sposób możesz upewnić się, że ciągi zostały zakodowane przy użyciu UTF-8, co zrobiłeś? –

+0

@ venus.w Przepraszam, nie mogę ci wiele pomóc. Czytam ciągi z DB i CSV zakodowane w UTF-8, ale po prostu zakładam, że kodowanie jest rzeczywiście UTF-8 (ponieważ jeśli wydrukuję mogę poprawnie odczytać znaki japońskie), ale mogą one być faktycznie zakodowane w innym zestawie znaków, który pozwala także na japońskie znaki. Wierzę, że istnieją funkcje Pythona, które mogą powiedzieć kodowanie ciąg, a nawet go zmienić. – Cesc

Odpowiedz

15

Terminal ma zestaw znaków, a Python wie, czym jest ten zestaw znaków, więc automatycznie rozszyfrowuje ciągi znaków Unicode do kodowania bajtowego używanego przez terminal, w twoim przypadku UTF-8.

Ale kiedy przekierujesz, nie używasz już terminala. Używasz teraz tylko rury uniksowej. Ta rura Uniksa nie ma zestawu znaków, a Python nie ma możliwości dowiedzenia się, które kodowanie jest teraz potrzebne, więc powróci do domyślnego zestawu znaków. Oznaczyłeś swoje pytanie słowem "Python-3.x", ale twoja składnia print to Python 2, więc podejrzewam, że faktycznie używasz Pythona 2. I wtedy Twój sys.getdefaultencoding() ogólnie jest 'ascii', aw twoim przypadku na pewno tak jest. Oczywiście nie można kodować znaków japońskich jako ASCII, więc pojawia się błąd.

Najlepszym rozwiązaniem przy korzystaniu z Pythona 2 jest kodowanie ciągu znaków przy pomocy UTF-8 przed jego wydrukowaniem. Wtedy przekierowanie zadziała, a wynikowy plik będzie miał UTF-8. Oznacza to, że nie będzie działać, jeśli twój terminal jest czymś innym, ale możesz uzyskać kodowanie terminala od sys.stdout.encoding i użyć tego (będzie to Brak podczas przekierowania w Pythonie 2).

W Pythonie 3 Twój kod powinien działać tak, jak jest, z tą różnicą, że musisz zmienić print mystring na print(mystring).

+0

tak to jest Python 2, właśnie sprawdzam, przepraszam za to. I masz rację, jeśli zrobię: print mystring.encode ('utf-8'), wtedy nie mam problemu z przekierowaniem. Dzięki za dokładne wyjaśnienie. – Cesc

+3

Możesz zmusić Pythona do używania innego kodowania również przy użyciu potoków ze zmienną środowiskową "PYTHONIOENCODING" (http://docs.python.org/2/using/cmdline.html#envvar-PYTHONEOENCODING). –

+0

Powiedziałeś, że "dekoduj ciąg z utf-8 przed jego wydrukowaniem", ale powinno to być "kodowanie unicode do UTF8 kodowanego str przed drukowaniem" (mystring.encode ('utf-8')). – AlbertFerras

2

Jeśli zostanie wyprowadzony do terminala, wówczas Python może sprawdzić wartość $LANG, aby wybrać zestaw znaków. Wszystkie zakłady są wyłączone, jeśli przekierujesz.