Python má pro práci s textem dva datové typy str a unicode.
Datový typ unicode je řetěze, který pochopitelně používá k��dování Unicode. Interní formát je ucs2 nebo ucs4 (záleží na nastavení při překladu), ale to nás prakticky nemusí zajímat, funkce na překódování se automaticky starají o správný převod.
Oproti tomu datový typ str je vlastně jen sekvence bajtů, v které může být cokoli. Dokonce i binární data včetně znaku s kódem 0 na rozdíl od jazyka C. Tudíž v str proměnné může být jakýkoli text v libovolném kódování. Programátor si musí sám někde udržovat informaci o tom, co to je a jaké to má kódování.
Viz následující ukázky v interaktivním interpretu, které probíhají v terminálu s utf-8 kódováním, takže zadaný text je v kódování utf-8.
Nejprve do proměnné text načteme z příkazového řádku (terminálu) nějaký text. V praxi může být jeho původ odkudkoli, načtený ze souboru, databáze, webu a podobně:
>>> text = raw_input() ěščřžýáíé
Ověříme si datový typ proměnné:
>>> type(text) <type 'str'>
Text můžeme na terminál zpátky vypsat:
>>> print text ěščřžýáíé
A také se můžeme potívat na reprezentační řetězec, který nám proměnnou text zobrází jako sekvenci bajtů:
>>> text '\xc4\x9b\xc5\xa1\xc4\x8d\xc5\x99\xc5\xbe\xc3\xbd\xc3\xa1\xc3\xad\xc3\xa9'
Vysvětlení pro ty, kteří tomuto výpisu nerozumí. Jedná se o řadu bajtových literálů. Bajtový literál je text '\xNN', kde NN je hodnota bajtu zapsaný v hexadecimální (šestnáctkové) soustavě. Příklad několika hodnot napsaných hexadecimální a poté decimální (desítkové) soustavě:
00 = 0, 09 = 9, 0a = 10, 0f = 15, 10 = 16, ff = 255
Na tomto výpisu si můžeme snadno spočítat, že náš text o devíti znacích v utf-8 zabírá 18 bajtů. To proto, že české znaky s diakritikou se v utf-8 zapisují pomocí dvou bajtů každý. Velikost si můžeme ověřit i takto:
>>> len(text) 18Kdybychom chtěli vědět, ne kolik text zabírá bajtů, ale kolik má znaků, máme u datového typu str smůlu. Python neví v jakém kódování je text, a jak má jednotlivé bajty interpretovat. Pro Python je to prostě sekvence 18 bajtů, které nerozumí. Pokud bychom chtěli s textem pracovat opravdu jako s textem a ne sekvencí bajtů, pak text musíme převést na datový typ unicode. To můžeme udělat dvěma různými způsoby:
>>> utext1 = unicode(text, 'utf-8') >>> utext2 = text.decode('utf-8')
Ještě si ověříme, zda jsou oba výsledky totožné.
>>> utext1 == utext2 True
Ano, jsou, proto každý může použít funkci, která je mu bližší a já už mohu dál pracovat jen s prvním výsledkem. Nejprve si ukážeme, že výsledek má opravdu datový typ unicode:
>>> type(utext1) <type 'unicode'>
Díky tomu si můžeme nechat spočítat počet znaků textu, protože len() u unicode nevrací velikost textu v bajtech, ale v počtech znaků:
>>> len(utext1) 9
A pro kontrolu si unicode text i vypíšeme na terminál:
>>> print utext1 ěščřžýáíé
Možná se někdo správně diví, jak je možné, že vypisujeme unicode ve formátu ucs2 nebo ucs4 na terminál s utf-8 a všechno vypadá v pořádku. Je to díky tomu, že příkaz print je inteligentní, a při výpisu text automaticky zkonvertuje zpátky na utf-8. Jak pozná, že má použít zrovna tohle kódování nevím, ale i v českých windows na každý pád správně pozná, že má použít cp852.
Ale to je výjimka, protože například při zápisu do souboru, nebo i přímém zápisu do terminálu už žádné inteligentní rozpoznávání nepoužívá a o správné překódování se musíme postarat sami. Bez toho často dopadneme s touto chybou:
>>> import sys >>> sys.stdout.write(utext1) Traceback (most recent call last): File "", line 1, in ? UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-8: ordinal not in range(128)
Chybové hlášení říká, že došlo k chybě při překódování unicode textu, a že ascii kodek nemůže překódovat znaky na pozici 0 až 8. Když totiž text z unicode nepřekódujeme my, pak se o to Python pokusí sám. Jako cílové kódování použije výchozí kódování pythonu, které je přednastaveno na ASCII.
ASCII kódování je sedmibitové, obsahuje tedy jen 128 znaků. Jsou v něm písmena anglické abecedy, čísla, interpunkční znaménka a podobné základní znaky pro anglicky píšící lidi. Nejsou v něm žádné české znaky s diakritikou, kterých je náš pokusný text plný. To je problém, protože právě proto text s českými diakritickými znaky není možné na ASCII bezchybně převést a to způsobí v Pythonu vyvolání výjimky UnicodeEncodeError.
Řešení jsou dvě, změnit výchozí kódování, nebo provést konverzi ručně. To první je poněkud koplikované, to druhé se dá provést například do utf-8 takto:
>>> sys.stdout.write(utext1.encode('utf-8')) ěščřžýáíé