Nacházíte se zde: Domů Ponořme se do Pythonu 3

Úroveň obtížnosti: ♦♦♦♢♢

Řetězce

I’m telling you this ’cause you’re one of my friends.
My alphabet starts where your alphabet ends!
(Protože jedním z mých přátel jsi, tak říkám ti:
Má abeceda začíná tam, kde tvá končí!)
— Dr. Seuss, On Beyond Zebra!

 

Pár nudných věcí, kterým musíte rozumět dříve, než se budeme moci ponořit

Přemýšlí o tom jen málo lidí, ale text je neuvěřitelně komplikovaný. Začněme s abecedou. Obyvatelé Bougainville používají nejmenší abecedu na světě. Jejich abeceda Rotokas se skládá z pouhých 12 písmen: A, E, G, I, K, O, P, R, S, T, U a V. Na opačném konci spektra najdeme jazyky, jako jsou čínština, japonština a korejština, které používají tisíce znaků. Angličtina používá 26 písmen — nebo 52, pokud počítáte zvlášť malá a velká písmena — a k tomu pár interpunkčních znaků, jako jsou !@#$%&.

Pokud v souvislosti s počítači mluvíte o „textu“, pak pravděpodobně myslíte „znaky a symboly na počítačové obrazovce“. Ale počítače nepracují se znaky a symboly. Pracují s bity a bajty. Každý kousek textu, který jste kdy spatřili na počítačové obrazovce, byl ve skutečnosti uložen v určitém znakovém kódování. Zhruba řečeno, kódování znaků zachycuje vztah mezi tím, co vidíte na obrazovce, a tím, co je ve skutečnosti uloženo v paměti počítače a na disku. Znakových kódování se používá velmi mnoho. Některá jsou optimalizována pro konkrétní jazyk, jakým je ruština, čínština nebo angličtina. Jiná kódování se mohou používat pro více jazyků.

Ve skutečnosti je to ještě mnohem komplikovanější. Řada znaků je společná pro více různých kódování, ale každé kódování může pro jejich uložení v paměti nebo na disku používat jinou posloupnost bajtů. Takže o znakovém kódování můžete uvažovat jako o dešifrovacím klíči. Kdykoliv vám někdo poskytne posloupnost bajtů — soubor, webovou stránku, cokoliv — a bude tvrdit, že to je „text“, budete k úspěšnému dekódování bajtů na znaky chtít vědět také to, jaké kódování znaků bylo použito. Pokud vám někdo poskytne špatný klíč nebo vám dokonce nedá žádný, postaví vás před nevyhnutelný úkol rozlousknout kód sami. Může se stát, že při tom uděláte chybu a výsledek bude zmatený.

Určitě už jste viděli webové stránky s podivnými znaky podobnými otazníku na místech, kde měly být apostrofy. Obvykle to znamená, že autor stránky neuvedl jejich správné kódování a váš prohlížeč musel hádat. Výsledkem byla směs očekávaných a neočekávaných znaků. U anglického textu to vnímáme spíš jen rušivě, ale v jiných jazycích může být výsledek zcela nečitelný.

Každý význačný jazyk na světě má definováno své znakové kódování. Každé kódování znaků bylo kvůli rozdílům v jazycích optimalizováno pro konkrétní jazyk, protože paměťový a diskový prostor byly v minulosti velmi drahé. Mám tím na mysli to, že pro reprezentaci znaků jazyka používalo každé kódování stejný interval čísel (0–255). Pravděpodobně znáte například kódování ASCII, které ukládá anglické znaky jako čísla z intervalu 0 až 127. (65 je velké „A“, 97 je malé „a“ atd.) Angličtina má velmi jednoduchou abecedu, která může být úplně vyjádřena méně než 128 čísly. Pro ty z vás, kteří umí počítat ve dvojkové soustavě, na to stačí 7 z 8 bitů v bajtu.

Západoevropské jazyky, jakou jsou francouzština, španělština a němčina, používají více znaků než angličtina. Přesněji řečeno, najdete v nich písmena kombinovaná s různými diakritickými značkami, jako například u znaku ñ používaného ve španělštině. Nejběžnějším kódováním je u těchto jazyků CP-1252. Označuje se také „windows-1252“, protože se široce používá v Microsoft Windows. Kódování CP-1252 sdílí znaky v intervalu 0–127 s ASCII, ale rozpíná se i do intervalu 128–255. Nalezneme v něm takové znaky jako n-s-vlnkou (241), u-s-přehláskou (252) atd. Pořád ale jde o jednobajtové kódování. Největší možné číslo (255) se pořád vejde do jednoho bajtu.

Pak tu ale máme jazyky, jako je čínština, japonština a korejština, které používají takové množství znaků, že vyžadují vícebajtové znakové sady. Každý jejich „znak“ je vyjádřen dvoubajtovým číslem v intervalu 0–65535. Ale u různých vícebajtových kódování se pořád setkáváme se stejným problémem, jako u různých jednobajtových kódování. Každé z nich používá stejná čísla pro vyjádření různých věcí. Používají jen širší interval čísel, protože musí vyjádřit mnohem více znaků.

Ve světě, který ještě nebyl propojen sítí a kde „text“ bylo něco, co jste si sami napsali a příležitostně vytiskli, to většinou bylo přijatelné. „Prostého textu“ jste ale moc nenašli. Zdrojové texty byly v ASCII a všichni ostatní používali textové procesory, které definovaly své vlastní (netextové) formáty. Ty si spolu s informacemi o stylu ukládaly také informaci o znakovém kódování. Lidé tyto dokumenty četli prostřednictvím stejných textových procesorů, jaké použil původní autor, takže všechno víceméně fungovalo.

Teď si představte vzestup globálních sítí s elektronickou poštou a s webem. Spousty „prostých textů“ létají kolem zeměkoule — byly napsány na jednom počítači, přeneseny přes druhý a zobrazovány na třetím počítači. Počítače vidí jen čísla. Ale čísla mohou znamenat různé věci. Ach ne! Co budeme dělat? Takže systém musel být navržen tak, aby si každý „prostý text“ s sebou nesl informaci o kódování. Připomeňme si, že jde o dešifrovací klíč, který převádí čísla srozumitelná počítači na znaky čitelné člověkem. Chybějící dešifrovací klíč vede ke zkreslenému textu, zmatkům nebo k něčemu horšímu.

Teď si představte, že bychom více kusů textu chtěli uložit na stejném místě, jako například ve stejné databázové tabulce uchovávající doručenou elektronickou poštu. Pro každý kousek musíme stejně uložit i znakové kódování, abychom text dokázali správně zobrazit. Myslíte si, že je to příliš tvrdý požadavek? Zkuste ve své e-mailové databázi vyhledávat. To znamená, že budete muset za běhu provádět převody mezi různými kódováními. Tady přestává legrace, že?

Teď si představte, že byste měli vícejazyčné dokumenty, ve kterých se znaky z různých jazyků vyskytují vedle sebe, v tom samém dokumentu. (Nápověda: Programy, které se o to pokoušely, typicky používaly pomocné kódy (escape) pro přepínání „režimů“. Prásk, teď jste v ruském režimu koi8-r, takže 241 znamená Я; bum, teď jste řeckém režimu pro Mac, takže 241 znamená ώ.) I v takových dokumentech byste samozřejmě chtěli umět vyhledávat.

Tak a teď plačte, protože vše, co jste si mysleli, že o řetězcích víte, je vám k ničemu. Nic takového jako „prostý text“ neexistuje.

Unicode

Vstupte do světa Unicode.

Unicode je systém navržený tak, aby bylo možné vyjádřit každý znak z každého jazyka. Každé písmeno, znak nebo ideogram se v Unicode vyjadřují jako 4bajtové číslo. Každé číslo vyjadřuje jedinečný znak, který se používá alespoň v jednom jazyce našeho světa. (Ne všechna čísla jsou využita, ale těch použitých je více než 65535. To znamená, že dva bajty nestačí.) Znaky, které se používají ve více jazycích, mají obvykle stejné číslo — pokud neexistuje dobrý etymologický důvod, aby tomu tak nebylo. Bez ohledu na další okolnosti je ale pro každý znak vyhrazeno jedno číslo a pro každé číslo jen jeden znak. Jedno číslo vždy znamená jedinou věc. Nepoužívají se žádné dříve zmíněné „režimy“. U+0041 znamená vždy 'A', a to i v případech, pokud by váš jazyk 'A' nepoužíval.

Na první pohled to vypadá jako výborná myšlenka. Jedno kódování vládne všem. Více jazyků v jednom dokumentu. Už nikdy více „přepínání režimu“ uprostřed textu jen kvůli přepnutí kódování. Ale už v této chvíli by vás měla napadnout zjevná otázka. Čtyři bajty? Pro každý jeden znak To vypadá jako hrozné plýtvání. Obzvlášť pro jazyky, jako jsou angličtina nebo španělština, které k vyjádření každého používaného znaku potřebují méně než jeden bajt (256 čísel). Ve skutečnosti je to plýtvání i pro jazyky založené na ideogramech (jako je čínština), které na jeden znak nepotřebují nikdy více než dva bajty.

Existuje kódování Unicode, které používá čtyři bajty na znak. Nazývá se UTF-32, podle počtu 32 bitů, což jsou 4 bajty. UTF-32 je přímočaré kódování. Každé číslo uložené na čtyřech bajtech se reprezentuje jako Unicode znak se stejným číslem. Má to své výhody. Nejdůležitější z nich je ta, že N-tý znak řetězce můžeme zpřístupnit v konstantním čase. N-tý znak totiž začíná na 4×N-tém bajtu. Ale má to i nevýhody. Ta nejzjevnější je, že na každý podělaný znak potřebujeme čtyři bajty.

Znaků je v Unicode velmi mnoho, ale ukazuje se, že většina lidí nepoužije nikdy žádný, který by ležel mimo prvních 65535. Takže tu máme další kódování Unicode. Nazývá se UTF-16 (protože 16 bitů jsou 2 bajty). V UTF-16 se každý znak s číslem z intervalu 0–65535 kóduje do dvou bajtů. Pokud opravdu potřebujeme vyjádřit zřídka používané Unicode znaky z „astrální roviny“ (přesahující 65535), používá UTF-16 jisté špinavé triky. Nejzjevnější výhoda: UTF-16 je prostorově dvakrát efektivnější než UTF-32, protože pro uložení každého znaku potřebujeme jen dva bajty místo čtyř (s výjimkou těch, pro které to neplatí). A pokud budeme předpokládat, že řetězec neobsahuje žádné znaky z astrální roviny, můžeme snadno najít N-tý znak v konstantním čase. Ten předpoklad je docela dobrý, ale jen do doby, kdy to přestane platit.

Ale jak UTF-32, tak UTF-16 mají také méně zřejmé nevýhody. Různé počítačové systémy ukládají jednotlivé bajty různým způsobem. Tak například znak U+4E2D by mohl být v UTF-16 uložen buď jako 4E 2D nebo 2D 4E. Závisí to na tom, zda systém používá přístup big-endian (na menší adrese významnější bajt) nebo little-endian (na menší adrese méně významný bajt). (Pro UTF-32 existují dokonce ještě další možnosti uspořádání bajtů.) Pokud váš dokument nikdy neopustí váš počítač, je to v suchu — různé aplikace budou na stejném počítači používat stejné pořadí bajtů. Ale v okamžiku, kdy budete chtít dokument přenášet mezi systémy, třeba prostřednictvím webu nebo něčeho takového, budeme potřebovat způsob, jak vyjádřit námi používané pořadí uložených bajtů. V opačném případě by cílový systém neuměl zjistit, zda dvoubajtová posloupnost 4E 2D znamená U+4E2D nebo U+2D4E.

Vícebajtová kódování Unicode pro vyřešení tohoto problému definují „Byte Order Mark“ (značka pořadí bajtů; zkráceně BOM). Jde o speciální netisknutelný znak, který můžete vložit na začátek svého dokumentu, abyste dali najevo, v jakém pořadí jsou vaše bajty uvedeny. Pro UTF-16 je Byte Order Mark roven U+FEFF. Pokud obdržíte dokument v UTF-16 začínající bajty FF FE, pak víte, že jde o jedno z možných pořadí bajtů. Pokud začíná bajty FE FF, pak víte, že pořadí bajtů je obrácené.

Přesto UTF-16 není zcela ideální. Platí to zvláště v případech, kdy používáte velké množství ASCII znaků. Když o tom popřemýšlíte, dokonce i čínské webové stránky budou obsahovat velké množství ASCII znaků — všechny ty značky a atributy, které obklopují tisknutelné čínské znaky. Pokud umíme najít N-tý znak v konstantním čase, je to fajn. Ale pořád tu máme nepříjemný problém s těmi znaky z astrální roviny. To znamená, že nemůžete zaručit, že každý znak je uložen přesně na dvou bajtech. Takže ve skutečnosti nemůžete N-tý znak najít v konstantním čase — pokud si ovšem neudržujete oddělený index. A mezi námi, ve světě se nachází ohromné množství ASCII textů…

Těmito otázkami se už zabývali jiní a přišli s řešením:

UTF-8

UTF-8 je kódovací systém s proměnnou délkou. To znamená, že různé Unicode znaky zabírají různý počet bajtů. Pro ASCII znaky (A-Z atd.) používá UTF-8 jen jeden bajt na znak. Ve skutečnosti používá přesně tentýž bajt. Prvních 128 znaků (0–127) se v UTF-8 nedá rozlišit od ASCII. Znaky z „rozšířené latinky“, jako jsou ñ a ö, budou zabírat dva bajty. (Bajty zde nevyjadřují kód z Unicode tak jednoduchým způsobem, jako je tomu u UTF-16. Je do toho zataženo trošku složitější hraní si s bity.) Čínské znaky jako 中 zabírají tři bajty. Zřídka používané znaky z „astrální roviny“ zabírají čtyři bajty.

Nevýhody: Protože každý znak zabírá různý počet bajtů, je nalezení N-tého znaku operací o složitosti O(N). To znamená, že čím je řetězec delší, tím déle budeme znak na určené pozici vyhledávat. Při kódování znaků na bajty a dekódování bajtů na znaky se musíme navíc zabývat dalšími manipulacemi s bity.

Výhody: Kódovaní běžných ASCII znaků je extrémně efektivní. Při kódování znaků z rozšířené latinky není horší než UTF-16. Pro čínské znaky je lepší než UTF-32. A díky jednoznačnému způsobu manipulace s bity zde neexistují žádné problémy s pořadím bajtů. (To mi musíte věřit, protože to tady nebudu matematicky zdůvodňovat.) Dokument kódovaný v UTF-8 používá na každém počítači přesně stejnou posloupnost bajtů.

Ponořme se

V Pythonu 3 jsou všechny řetězce posloupnostmi znaků v Unicode. Nenajdeme zde nic takového jako pythonovský řetězec kódovaný v UTF-8 nebo pythonovský řetězec kódovaný v CP-1252. „Je tento řetězec v UTF-8?“ — toto je nesmyslná otázka. UTF-8 představuje způsob kódování znaků do posloupnosti bajtů. Pokud chcete vzít řetězec a přeměnit jej na posloupnost bajtů v určitém znakovém kódování, může vám v tom Python 3 pomoci. Pokud chcete vzít posloupnost bajtů a přeměnit ji na řetězec, pomůže vám s tím Python 3 také. Ale bajty nejsou znaky. Bajty jsou prostě bajty. Znak je abstrakce. A řetězce jsou posloupnostmi těchto abstrakcí.

>>> s = '深入 Python'    
>>> len(s)               
9
>>> s[0]                 
'深'
>>> s + ' 3'             
'深入 Python 3'
  1. Řetězec vytvoříme tak, že posloupnost znaků uzavřeme do uvozovacích znaků. Pythonovské řetězce mohou být definovány uzavřením buď do apostrofů ('; single quotes) nebo do uvozovek ("; double quotes).
  2. Zabudovaná funkce len() vrací délku řetězce, tj. počet znaků. Je to stejná funkce, jakou používáme pro nalezení délky seznamu, n-tice, množiny nebo slovníku. Řetězec připomíná n-tici znaků.
  3. S využitím indexové notace můžeme získat jednotlivé znaky řetězce, podobně jako u seznamu.
  4. Operátor + provádí konkatenaci řetězců (zřetězení, spojení), stejně jako u seznamů.

Formátovací řetězce

Podívejme se znovu na humansize.py:

[stáhnout humansize.py]

SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],         
            1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}

def approximate_size(size, a_kilobyte_is_1024_bytes=True):
    '''Convert a file size to human-readable form.                          

    Keyword arguments:
    size -- file size in bytes
    a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
                                if False, use multiples of 1000

    Returns: string

    '''                                                                     
    if size < 0:
        raise ValueError('number must be non-negative')                     

    multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
    for suffix in SUFFIXES[multiple]:
        size /= multiple
        if size < multiple:
            return '{0:.1f} {1}'.format(size, suffix)                       

    raise ValueError('number too large')
  1. 'KB', 'MB', 'GB'… to všechno jsou řetězce.
  2. Dokumentační řetězce funkcí jsou řetězce. Tento dokumentační řetězec se rozprostírá přes několik řádků. Proto je použita trojice apostrofů na začátku i na konci řetězce.
  3. Tato trojice apostrofů ukončuje dokumentační řetězec.
  4. Zde máme další řetězec, který předáváme objektu výjimky jako lidsky čitelnou podobu chybového hlášení.
  5. A tady máme… hej, co je sakra tohle?

Python 3 podporuje formátování hodnot do řetězců. Možné jsou i velmi komplikované výrazy, ale nejzákladnější použití spočívá ve vložení hodnoty do řetězce s jednou oblastí náhrad.

>>> username = 'mark'
>>> password = 'PapayaWhip'                             
>>> "{0}'s password is {1}".format(username, password)  
"mark's password is PapayaWhip"
  1. Ne, moje heslo doopravdy nezní PapayaWhip.
  2. Tady se děje spousta věcí. Zaprvé, voláme zde metodu řetězcového literálu. Řetězce jsou objekty a objekty mají metody. Zadruhé, vyhodnocením celého výrazu vznikne řetězec. Zatřetí, {0} a {1} jsou oblasti náhrad (replacement fields), do kterých budou dosazeny argumenty předané metodě format().

Složená jména oblastí

Předchozí příklad ukazoval nejjednodušší případ, kdy jsou v oblastech náhrad použita pouze celá čísla. Celá čísla se v oblastech náhrad považují za indexy do seznamu argumentů metody format(). To znamená, že {0} je nahrazena prvním argumentem (v našem případě username), {1} je nahrazena druhým argumentem (password) atd. Můžeme použít tolik pozičních indexů, kolik máme argumentů. A argumentů můžeme mít tolik, kolik chceme. Ale oblasti náhrad jsou ještě mnohem mocnější.

>>> import humansize
>>> si_suffixes = humansize.SUFFIXES[1000]      
>>> si_suffixes
['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
>>> '1000{0[0]} = 1{0[1]}'.format(si_suffixes)  
'1000KB = 1MB'
  1. Místo volání funkce z modulu humansize si půjčíme jednu z datových struktur, která je v něm definována: seznam přípon jednotek „SI“ (mocniny čísla 1000).
  2. Vypadá to složitě, ale není to složité. {0} se odkazuje na první argument předaný metodě format(), tedy na si_suffixes. Ale si_suffixes má podobu seznamu. Takže {0[0]} odkazuje na první položku seznamu, který je prvním argumentem předaným metodě format(): 'KB'. Podobně {0[1]} odkazuje na druhou položku stejného seznamu: 'MB'. Všechno vně složených závorek — včetně 1000, rovnítka a mezer — zůstává nedotčeno. Konečným výsledkem je řetězec '1000KB = 1MB'.

Tento příklad ukazuje, že specifikátory formátu mohou pro zpřístupnění položek a vlastností datových struktur používat (téměř) pythonovskou syntaxi. Říká se tomu složená jména oblastí (compound field names). Funkční jsou následující složená jména oblastí:

Abych vás ohromil, tady máte příklad, který vše kombinuje:

>>> import humansize
>>> import sys
>>> '1MB = 1000{0.modules[humansize].SUFFIXES[1000][0]}'.format(sys)
'1MB = 1000KB'

A teď si popíšeme, jak to funguje:

Specifikátory formátu

Ale počkat! Ono je toho ještě víc! Podívejme se ještě jednou na tento divný řádek kódu ze souboru humansize.py:

if size < multiple:
    return '{0:.1f} {1}'.format(size, suffix)

{1} je nahrazena druhým argumentem předaným metodě format(), a tím je suffix. Ale co znamená {0:.1f}? Jde o dvě věci: význam {0} už znáte, ale význam :.1f ještě ne. Druhá část (dvojtečka a to, co následuje) definuje specifikátor formátu (format specifier), který upřesňuje, jak má být dosazovaná hodnota formátována.

Specifikátory formátu vám dovolí upravit výsledný text do řady užitečných podob — podobně jako funkce printf() v jazyce C. Můžete přidat vycpávku z nul nebo z mezer, zarovnat řetězce, řídit počet desetinných míst a dokonce konvertovat čísla do šestnáctkové soustavy.

Dvojtečka (:) uvnitř oblasti náhrad označuje začátek specifikátoru formátu. Specifikátor „.1“ znamená „zaokrouhli na nejbližší desetiny“ (tj. zobraz jen jedno místo za desetinnou tečkou). Specifikátor „f“ znamená „číslo s pevnou řádovou čárkou“ (jako opak k exponenciálnímu zápisu nebo k jiným způsobům reprezentace čísla). Takže pokud má size hodnotu 698.24 a suffix hodnotu 'GB', pak naformátovaný řetězec bude mít podobu '698.2 GB'. Hodnota 698.24 bude zaokrouhlena na jedno desetinné místo a hodnota suffix bude připojena za číslo.

>>> '{0:.1f} {1}'.format(698.24, 'GB')
'698.2 GB'

Detaily kolem specifikátorů formátů naleznete v oficiální pythonovské dokumentaci, v části Format Specification Mini-Language.

Další běžné metody řetězců

S řetězci můžeme, kromě formátování, provádět řadu dalších užitečných kousků.

>>> s = '''Finished files are the re-  
... sult of years of scientif-
... ic study combined with the
... experience of years.'''
>>> s.splitlines()                     
['Finished files are the re-',
 'sult of years of scientif-',
 'ic study combined with the',
 'experience of years.']
>>> print(s.lower())                   
finished files are the re-
sult of years of scientif-
ic study combined with the
experience of years.
>>> s.lower().count('f')               
6
  1. V interaktivním pythonovském shellu můžeme zadat i víceřádkové řetězce. Pokud zahájíme víceřádkový řetězec uvedením trojitého uvozovacího znaku, můžeme jednoduše stisknout ENTER a interaktivní shell nás vyzve k zadání pokračování řetězce. Zapsáním uzavírací trojice uvozovacího znaku označíme konec řetězce. Po následném stisku ENTER se příkaz provede. (V tomto případě bude řetězec přiřazen do proměnné s).
  2. Metoda splitlines() přebírá jeden víceřádkový řetězec a vrací seznam řetězců, ve kterém každá položka reprezentuje jeden řádek z originálu. Všimněte si, že znaky konců řádků nejsou do jednotlivých řádků zahrnuty.
  3. Metoda lower() převádí celý řetězec na malá písmena. (Podobně zase metoda upper() převádí řetězec na velká písmena.)
  4. Metoda count() vrací počet výskytů zadaného podřetězce. Ano, v uvedené větě je opravdu šest „f“!

Vezměme si další běžný případ. Dejme tomu, že máme seznam dvojic klíč-hodnota ve tvaru key1=value1&key2=value2 a my bychom je chtěli rozdělit a vytvořit z nich slovník v podobě {key1: value1, key2: value2}.

>>> query = 'user=pilgrim&database=master&password=PapayaWhip'
>>> a_list = query.split('&')                                        
>>> a_list
['user=pilgrim', 'database=master', 'password=PapayaWhip']
>>> a_list_of_lists = [v.split('=', 1) for v in a_list if '=' in v]  
>>> a_list_of_lists
[['user', 'pilgrim'], ['database', 'master'], ['password', 'PapayaWhip']]
>>> a_dict = dict(a_list_of_lists)                                   
>>> a_dict
{'password': 'PapayaWhip', 'user': 'pilgrim', 'database': 'master'}
  1. Řetězcové metodě split() jsme zadali jeden argument, hodnotu oddělovače. Metoda v místech zadaného oddělovače rozdělí řetězec na seznam řetězců. Zde je jako oddělovač použit znak ampersand, ale může to být cokoliv.
  2. Teď máme seznam řetězců, kde každý obsahuje klíč, následuje znak rovnítka a poté hodnota. K průchodu tímto seznamem a k rozdělení každého řetězce na dva v místě rovnítka můžeme použít generátorovou notaci seznamu (list comprehension). Druhý nepovinný argument metody split() říká, kolikrát chceme dělení řetězce provést. Hodnota 1 znamená „rozdělit jen jednou“, takže metoda split() vrátí dvouprvkový seznam. (Hodnota by teoreticky mohla také obsahovat znak rovnítka. Pokud bychom použili pouze 'key=value=foo'.split('='), dostali bychom seznam s třemi prvky ['key', 'value', 'foo'].)
  3. A nakonec necháme Pythonu převést tento seznam seznamů na slovník jednoduše tím, že jej předáme funkci dict().

Předchozí příklad se hodně podobá získávání parametrů dotazu uvedeného v URL, ale rozklad opravdu používaných URL je ve skutečnosti složitější. Pokud se máte zabývat parametry dotazu v URL, pak pro vás bude mnohem lepší, když použijete funkci urllib.parse.parse_qs(). Ta je schopná zvládnout i některé ne příliš zřejmé hraniční případy.

Vykrajování podřetězců

Jakmile máme vytvořen řetězec, můžeme získat jakoukoliv jeho část v podobě nového řetězce. Anglicky se tomu říká „slicing the string“, což můžeme přeložit jako „vykrajování z řetězce“ nebo „výřez z řetězce“. Vykrajování podřetězců funguje naprosto stejně jako vykrajování podseznamů. Ono to dává smysl, protože řetězce jsou prosté posloupnosti znaků.

>>> a_string = 'My alphabet starts where your alphabet ends.'
>>> a_string[3:11]           
'alphabet'
>>> a_string[3:-3]           
'alphabet starts where your alphabet en'
>>> a_string[0:2]            
'My'
>>> a_string[:18]            
'My alphabet starts'
>>> a_string[18:]            
' where your alphabet ends.'
  1. Část řetězce, výřez (slice), můžeme získat zadáním dvou indexů. Návratovou hodnotou je nový řetězec, který obsahuje všechny znaky (při zachování pořadí) počínaje prvním indexem výřezu a konče znakem před druhým indexem.
  2. Při vykrajování z řetězců můžeme rovněž použít záporné indexy výřezu, stejně jako u seznamu.
  3. Řetězce se indexují od nuly, takže zápis a_string[0:2] vrací první dva znaky řetězce počínaje znakem a_string[0] až po a_string[2] vyjma (ten už ve výsledku nebude).
  4. Pokud je levý index výřezu roven nule, můžeme nulu vynechat. Bude dosazena implicitně. Takže zápis a_string[:18] je stejný jako a_string[0:18]. Počáteční nula se dosadí jako implicitní hodnota.
  5. Podobně, pokud by pravý index výřezu měl mít hodnotu rovnou délce řetězce, můžeme jej vynechat. Takže a_string[18:] je totéž jako a_string[18:44], protože v tomto řetězci se nachází 44 znaků. A najdeme zde opět potěšitelnou symetrii. Pro tento 44znakový řetězec vrací zápis a_string[:18] prvních 18 znaků a a_string[18:] vrací vše kromě prvních 18 znaků. Obecně platí, že a_string[:n] vždy vrátí prvních n znaků a a_string[n:] vrátí zbytek — nezávisle na délce řetězce.

Řetězce vs. bajty

Bajty jsou bajty, znaky jsou abstrakce. Neměnitelná posloupnost Unicode znaků se nazývá řetězec. Neměnitelná posloupnost čísel z intervalu 0–255 se nazývá objekt typu bytes.

>>> by = b'abcd\x65'  
>>> by
b'abcde'
>>> type(by)          
<class 'bytes'>
>>> len(by)           
5
>>> by += b'\xff'     
>>> by
b'abcde\xff'
>>> len(by)           
6
>>> by[0]             
97
>>> by[0] = 102       
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'bytes' object does not support item assignment
  1. Objekt typu bytes definujeme použitím b'', tedy syntaxe pro „bajtový literál“ . Každý bajt uvnitř bajtového literálu může být buď ASCII znak, nebo zakódované šestnáctkové číslo od \x00 do \xff (0–255).
  2. Bajtový objekt je typu bytes.
  3. Délku obsahu objektu typu bytes můžeme získat zabudovanou funkcí len(), tedy stejně jako u seznamů a řetězců.
  4. A stejně jako u seznamů a řetězců, pro konkatenaci (zřetězení, spojení) objektů typu bytes můžeme použít operátor +. Výsledkem je nový objekt typu bytes.
  5. Zřetězením 5bajtového objektu a jednobajtového objektu typu bytes vznikne 6bajtový objekt typu bytes.
  6. Stejně jako u seznamů a řetězců můžeme jednotlivé bajty z objektu typu bytes zpřístupnit indexovou notací. Položkami řetězců jsou znaky, položkami objektu typu bytes jsou čísla. Konkrétně jsou to celá čísla z intervalu 0–255.
  7. Objekt typu bytes je neměnitelný (immutable). Jednotlivým bajtům nemůžeme nic přiřadit. Pokud potřebujete měnit jednotlivé bajty, můžete buď použít výřezy (slicing) a operátor konkatenace (fungují stejně jako u řetězců), nebo můžete objekt typu bytes konvertovat na objekt typu bytearray.
>>> by = b'abcd\x65'
>>> barr = bytearray(by)  
>>> barr
bytearray(b'abcde')
>>> len(barr)             
5
>>> barr[0] = 102         
>>> barr
bytearray(b'fbcde')
  1. Pro konverzi objektu typu bytes na objekt měnitelného typu bytearray použijte zabudovanou funkci bytearray().
  2. Všechny metody a operace, které můžete provádět s objektem typu bytes, můžete provádět i s objektem typu bytearray.
  3. Jedním z rozdílů je to, že objektu typu bytearray můžete při využití indexové notace přiřazovat hodnoty jednotlivým bajtům. Přiřazovaná hodnota musí být celé číslo v intervalu 0–255.

Jednou z věcí, které nikdy nemůžete udělat, je míchání bajtů s řetězci.

>>> by = b'd'
>>> s = 'abcde'
>>> by + s                       
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't concat bytes to str
>>> s.count(by)                  
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'bytes' object to str implicitly
>>> s.count(by.decode('ascii'))  
1
  1. Bajty a řetězce nelze spojovat. Jsou různých datových typů.
  2. Nemůžete spočítat výskyt bajtů v řetězci, protože v řetězci žádné bajty nejsou. Řetězec je posloupností znaků. Možná jste měli na mysli „spočítej výskyty řetězce, který bychom získali po dekódování této posloupnosti bajtů při použití určitého znakového kódování“? V pořádku, ale budete to muset zapsat explicitně. Python 3 neprovádí implicitní konverzi bajtů na řetězce a řetězců na bajty.
  3. Překvapivou shodou okolností tento řádek kódu říká „spočítej výskyty řetězce, který bychom získali po dekódování této posloupnosti bajtů při určitém znakovém kódování“.

A tady máme spojení mezi řetězci a bajty: objekt typu bytes má metodu decode(), která přebírá znakové kódování a vrací řetězec. A řetězce zase mají metodu encode(), která přebírá znakové kódování a vrací objekt typu bytes. V předchozím případě bylo dekódování poměrně přímočaré — co se týká konverze posloupnosti bajtů v kódování ASCII na řetězec znaků. Ale stejný postup funguje pro libovolné kódování, které odpovídá znakům řetězce. Platí to dokonce i pro historická (ne Unicode) kódování.

>>> a_string = '深入 Python'         
>>> len(a_string)
9
>>> by = a_string.encode('utf-8')    
>>> by
b'\xe6\xb7\xb1\xe5\x85\xa5 Python'
>>> len(by)
13
>>> by = a_string.encode('gb18030')  
>>> by
b'\xc9\xee\xc8\xeb Python'
>>> len(by)
11
>>> by = a_string.encode('big5')     
>>> by
b'\xb2`\xa4J Python'
>>> len(by)
11
>>> roundtrip = by.decode('big5')    
>>> roundtrip
'深入 Python'
>>> a_string == roundtrip
True
  1. Toto je řetězec. Má devět znaků.
  2. Toto je objekt typu bytes. Obsahuje 13 bajtů. Posloupnost bajtů vznikla zakódováním řetězce a_string do UTF-8.
  3. Tento objekt typu bytes obsahuje 11 bajtů. Vznikl zakódováním řetězce a_string v kódování GB18030.
  4. Toto je objekt typu bytes. Má 11 bajtů. Jde o zcela jinou posloupnost bajtů, která vznikla zakódováním řetězce a_string v kódování Big5.
  5. Toto je řetězec. Má devět znaků. Jde o posloupnost znaků, kterou jsme získali, když jsme objekt by dekódovali algoritmem Big5. Shoduje se s původním řetězcem.

Závěrečná poznámka: Kódování znaků v pythonovském zdrojovém textu

Python 3 předpokládá, že váš zdrojový kód — tj. každý soubor s příponou .py — je uložen v kódování UTF-8.

V Pythonu 2 bylo u souborů s příponou .py výchozím kódováním ASCII. V Pythonu 3 je výchozím kódováním UTF-8.

Pokud byste ve svých zdrojových textech chtěli používat jiné kódování, můžete na první řádek souboru vložit deklaraci použitého kódování. Tato deklarace říká, že soubor .py používá kódování windows-1252:

# -*- coding: windows-1252 -*-

Z technického pohledu můžete deklaraci použitého kódování umístit i na druhý řádek. Na prvním řádku se může vyskytovat UNIXovský magický příkazový komentář (hash-bang command).

#!/usr/bin/python3
# -*- coding: windows-1252 -*-

Více informací naleznete v PEP 263: Defining Python Source Code Encodings.

Přečtěte si

O Unicode v jazyce Python:

O Unicode obecně:

O znakovém kódování v jiných formátech:

O řetězcích a jejich formátování:

© 2001–11 Mark Pilgrim