Uživatelské nástroje

Nástroje pro tento web


prog:string

Řetězce

S řetězci jako s jedním ze základních datových typů jazyka Python jsme se velmi stručně seznámili v úvodní lekci. Slouží k uchování informací v textové podobě, která se skládá z jednotlivých znaků. Znakem rozumíme písmeno (např. q, Č, β), číslici (5), tisknutelný symbol (=, §, ©, , mezera) nebo jiný symbol (tabulátor, odřádkování). Řetězec se může skládat z jednoho nebo více znaků, může však být i prázdný1).

Řetězcové konstanty

Při inicializaci proměnných, jako argumenty funkcí nebo členy ve výrazech potřebujeme zapsat řetězcové konstanty. K tomu využíváme zápis znaků mezi uvozovky nebo apostrofy.

"Řetězcová konstanta jazyka Python pomocí uvozovek."
'Jiný text pomocí apostrofů.'
'Lze vložit i znak " do řetězce,'
"stejně tak jako znak ' (tj. apostrof)."

Úvodní a závěrečné uvozovky (resp. apostrofy) nejsou součástí řetězce. Speciální znaky vkládáme pomocí symbolu zpětného lomítka:

  • odřádkování \n (je to jeden znak!)
  • tabulátor \t (může pomoci s formátováním tabulek)
  • uvozovka \" (takto lze vložit uvozovky i do konstanty ohraničené uvozovkami)
  • apostrof \' (totéž pro situaci s apostrofy)
  • zpětné lomítko \\
>>> print("Tabulka\n1\t2\t3\n\'a\'\t\"b\"\ta \\ b")
Tabulka
1	2	3
'a'	"b"	a \ b

Dlouhé řetězce zapíšeme na více řádků pomocí rozdělovacího zpětného lomítka

"První řádek,\
po něm druhý\
a třetí nakonec."

nebo pomocí trojitých uvozovek """...""" či trojitých apostrofů '''...'''.

"""Příklad řetězce rozděleného
na více řádků - to jsme již viděli
u dokumentačních řetězců ve funcích."""

Délka řetězce

Délku řetězce (tj. počet znaků, ze kterých se skládá) určíme pomocí vestavěné funkce len.

len("slovo")                          # => 5
len('\n')                             # => 1
len('')                               # => 0 (prázdný řetězec)

Operace s řetězci

V jazyce Python se řetězce (proměnné, konstanty, funkce s řetězcovou návratovou hodnotou) mohou také vyskytovat ve výrazech:

  • součet řetězců se vyhodnotí jako řetězec vzniklý spojením řetězců za sebou
"To " + "je " + "celá " + "věta."     # => 'To je celá věta.'
  • součin řetězce a přirozeného čísla n se vyhodnotí jako n-násobné opakování řetězce
4 * "Haf! "                           # => 'Haf! Haf! Haf! Haf! '
"-" * 8                               # => '--------'
  • zjištění, zda znak či řetězec je (logický operátor in) nebo není (logický operátor not in) obsažen v jiném řetězci
"a" in "abeceda"                      # => True 
"ece" not in "abeceda"                # => False
"pra" in "Praha"                      # => False (velikost písmen!)
"" in "Praha"                         # => True
"Praha" in "Praha"                    # => True

Přístup k jednotlivým znakům

Přístup k jednotlivým znakům řetězce je možný pomocí indexování, tj. určení polohy znaku číselným indexem. Znaky se číslují od nuly, první znak má index 0, druhý 1, atd. Indexování se zapisuje hranatými závorkami.

txt = 'klíče'        
txt[0]                                # => 'k'
txt[1]                                # => 'l'
txt[4]                                # => 'e'

Je potřeba dávat pozor na povolený rozsah indexu, který musí být menší než délka řetězce. Můžeme indexovat znaky i od konce, pak -1 odpovídá poslednímu znaku, -2 předposlednímu atd., překročení povoleného rozsahu opět vede k chybě.

txt = 'klíče'        
txt[-1]                               # => 'e'
txt[-2]                               # => 'č'
txt[-5]                               # => 'k'
index od začátku 0 1 2 3 4
k l í č e
index od konce -5 -4 -3 -2 -1

S pomocí indexování je velmi snadné vypsat zadaný text po jednom znaku na každý řádek pomocí cyklu.

text = 'klíče'
for index in range(len(text)):
    print(text[index])

:!: Existuje však i mnohem elegantnější možnost, ve které je v každém průchodu cyklu for přiřazen do řídicí proměnné přímo jeden znak (od prvního po poslední).

text = 'klíče'
for znak in text:
    print(znak)

Podřetězce

Pomocí jednoho indexu lze přistupovat k jednotlivým znakům v řetězci. Zobecněním je získání podřetězce pomocí dvou indexů2) - oba zapisujeme do hranatých závorek a oddělujeme je dvojtečkou. :!: Podobně jako u funkce range se počáteční index do rozsahu započítává, koncový nikoliv! Je možno používat nezáporné indexy pro počítání od počátku i záporné pro počítání od konce, případně je i kombinovat. Vynechaný index znamená úplný začátek (resp. konec) zdrojového řetězce. Nesmyslný interval nebo index mimo platný rozsah mají za výsledek prázdný řetězec.

text = "řetězcová konstanta v Pythonu"
text[2:7]            # => 'tězco' (znaky s indexem 2, 3, 4, 5, 6)
text[10:-10]         # => 'konstanta'
text[:3]             # => 'řet' (první 3 znaky)
text[-5:]            # => 'thonu' (posledních 5 znaků)
text[:]              # => 'řetězcová konstanta v Pythonu' (kopie)
text[5:5]            # => '' (rovnost počátečního a koncového indexu)
text[5:0]            # => '' (koncový index je menší než počáteční)

Pomocí třetího parametru (opět v analogii s funkcí range a opět odděleného dvojtečkou) lze do výsledku zahrnout pouze každý n-tý znak v intervalu.

text[0:10:3]         # => 'řěo ' (znaky s indexem 0, 3, 6, 9)
text[::2]            # => 'řtzoákntnavPtou' (znaky se sudým indexem)
text[1::2]           # => 'eěcv osat  yhn' (znaky s lichým indexem)

Kódování znaků a řazení řetězců

Počítače pracují interně s čísly, proto i textové řetězce jsou uloženy jako posloupnosti čísel. Python používá pro přiřazení čísel jednotlivým znakům normu Unicode. Čísla 0 až 127 (která se dají vyjádřit v 7 bitech) odpovídají starší normě ASCII, která uvažovala pouze velká a malá písmena anglické abecedy, číslice, základní symboly a tzv. řídicí znaky.

Kód znaku zjistíme pomocí funkce ord, předávaný parametr musí být jeden znak.

ord('a')                         # => 97
ord('c')                         # => 99
ord('A')                         # => 65
ord('č')                         # => 269
ord('Z')                         # => 90

Inverzní funkcí k ord je chr, která převádí přirozené číslo na jednoznakový řetězec.

chr(268)                         # => 'Č'
chr(269)                         # => 'č'

Do řetězcových konstant můžeme zapsat i znaky, které na klávesnici nenalezneme, potřebujeme ale znát jejich Unicode čísla (vyjádřená v hexadecimální soustavě).

"\xa9"                           # => '©' (za \x dvě hexa číslice)
"\xA92017"                       # => '©2017' ("\xA9" je jeden znak!)
"\u03b1\u03B2\u03b3"             # => 'αβγ' (za \u čtyři hexa číslice)
"Alef \U00002135"                # => 'Alef ℵ' (za \U osm hexa číslic)

Kódování znaků je pro nás důležité, pokud provádíme porovnávání řetězců pomocí relačních operátorů jako >, <= apod. Dva řetězce se porovnávají pomocí lexikografického uspořádání, tj. postupně se porovnávají znaky od začátku (podle jejich číselného kódu), dokud se nenarazí na rozdíl nebo je některý z operandů vyčerpán. Rovnost nastává pouze pro identické řetězce.

# všechny logické výrazy se vyhodnotí jako True
'ab' > 'Ab'                      # 97 > 65 pro 1. znak
'aa' > 'a'                       # 1. znak shodný, druhý operand vyčerpán
'ac' > 'aa'                      # 1. znak shodný, 99 > 97 pro 2. znak
'č' > 'Z'                        # 269 > 90

Jak vidíte, takovéto uspořádání3) rozhodně neodpovídá řazení slov v běžné praxi. Ukazuje se však, že se nejedná o úplně jednoduchý úkol - uvažte například odlišné zvyklosti v různých jazycích jako: ch je v češtině jedno písmeno, v angličtině dvě nebo oe a ö v němčině vyjadřují totéž.

Pokud se omezíme na anglické texty, pak můžeme přijatelného řazení dosáhnout tak, že před porovnáním vždy převedeme oba operandy na malá písmena pomocí metody lower (nebo na velká metodou upper). V plné obecnosti je naštěstí tato problematika důsledně řešena ve specializovaném modulu4).

Metody

Řetězce (stejně jako ostatní datové typy) jsou v jazyce Python objekty, což si představte jako něco, co dokáže uložit nějaká data a pomocí vlastních metod k nim přistupovat a provádět s nimi požadované operace. Metody mají stejně jako funkce parametry a návratovou hodnotu. Jejich volání provádíme pomocí tečkové notace objekt.metoda. Nemohou se vyskytovat samostatně, vždy musí být určeno, ke kterému objektu se vztahují. V následujícím textu str znamená libovolný objekt typu řetězec (konstanta, proměnná, …).

Nebudeme uvádět všechny metody, není ani nutné si všechny pamatovat. Je dobré mít o nich jisté povědomí, podrobnosti lze vždy dohledat v dokumentaci.

Informace o druhu znaků

Metody vrací hodnotu True, pokud je řetězec neprázdný a všechny znaky splňují konkrétní podmínku. Nemají žádný parametr.

str.islower() žádná velká písmena
str.isupper() žádná malá písmena
str.isspace() pouze oddělovače (mezery, odřádkování, tabulátory, …)
str.isalpha() pouze písmena
str.isdigit(), str.isdecimal() a str.isnumeric() pouze číselné symboly (stejné pro standardní číslice, liší se např. zahrnutím indexů, mocnin, zlomků, znaků pro nás exotických abeced)
str.isalnum() pouze číselné symboly a písmena
str.isprintable() všechny znaky mají tisknutelnou podobu

"".islower()                     # => False (prázdný řetězec)
"ká\u03b1".islower()             # => True (umí i české, řecké aj. znaky)
"více slov -12".islower()        # => True (mezera, minus ani číslice nevadí)
" \t\n".isspace()                # => True
"123".isdigit()                  # => True
"+123".isdecimal()               # => False (znaménko, des. tečka aj. vadí)
"více slov".isalpha()            # => False (mezera není písmeno)
"\n".isprintable()               # => False (odřádkování)

Počet výskytů podřetězce

str.count(vzor), str.count(vzor, od) a str.count(vzor, od, do) vrací počet (nepřekrývajících se) výskytů řetězce vzor (v celém řetězci, případně pouze ve vymezené části)

text = "Dloooooooouhé slovo"
text.count('oooo')               # => 2
text.count('o', -5)              # => 2
text.count('l', 5, 10)           # => 0

Vyhledávání podřetězce

Metody vyhledají první výskyt řetězce vzor v celém řetězci nebo určené části a vrátí index jeho počátku.

str.find(vzor), str.find(vzor, od), str.find(vzor, od, do) není-li vzor nalezen, je návratová hodnota -1
str.index(vzor), str.index(vzor, od), str.index(vzor, od, do) není-li vzor nalezen, je vyvolána chyba5)

Existují i metody rfind a rindex, které se od výše uvedených liší pouze tím, že prohledávání probíhá odzadu.

text = "Dloooooooouhé slovo"
text.find('oooo')                # => 2
text.find('oooo', 5)             # => 5
text.find('oooo', 5, 8)          # => -1 (nenalezeno, malý interval)
text.rfind('oooo')               # => 6

Úprava řetězce

Řada metod vrací řetězec, který vznikne nějakou úpravou zdrojových dat (tj. řetězce uloženého v objektu).

str.lower() všechna velká písmena jsou převedena na malá, ostatní znaky zachovány
str.upper() všechna malá písmena jsou převedena na velká, ostatní znaky zachovány
str.replace(vzor, nahrada) a str.replace(vzor, nahrada, pocet) všechny výskyty (případně jen jejich omezený počet pocet) řetězce vzor jsou nahrazeny řetězcem nahrada

str.ljust(delka) a str.ljust(delka, znak) pokud je parametr delka větší než současná délka řetězce, je tento rozšířen na délku delka a zarovnán doleva doplněním mezer (případně znaku znak). Pro zarovnání doprava máme analogickou metodu rjust a pro zarovnání na střed metodu center.

str.lstrip() slouží k odstranění počátečních mezer (obecněji tzv. bílých znaků). Varianta str.lstrip(znaky) provede odstranění všech počátečních znaků, které se vyskytují v řetězci znaky. I v tomto případě máme rstrip pro odstranění znaků na konci a strip na obou koncích.

"Škoda Fabia 1.2TSI".lower()     # => 'škoda fabia 1.2tsi'
"kolo jelo".replace("o","-O-",2) # => 'k-O-l-O- jelo'
"Python".center(20)              # => '       Python       '
"12.4".rjust(10, "_")            # => '______12.4'
" s mezerami   ".strip()         # => 's mezerami'
"cca +125".lstrip(" +abc")       # => '125'

Pro pokročilejší formátování máme metodu format, kterou se ještě budeme podrobněji zabývat.

Pro připomenutí

Již dříve jsme se seznámili s funkcemi, které provádějí konverzi řetězcové hodnoty na jiné datové typy (int, float, bool), a běžně je používali např. při zpracování vstupů. Funkce str převede hodnotu jiného datového typu na jeho textovou reprezentaci. Víme také, že řetězec vystupující jako logický výraz má hodnotu True, pokud je neprázdný.

Příklad

Pro ilustraci použití některých výše popsaných operací, funkcí a metod řetězců uvádíme krátký program, který vytiskne tabulku ASCII znaků (tj. s kódy do 128) po 16 na jeden řádek.

ascii.py
sloupcu = 16
# titulek
print(" " * 6 + "Tabulka znaků ASCII".center(4 * sloupcu))
print()
# hlavička tabulky
print(" " * 6, end = "")
for i in range(sloupcu):
    print(str(i).rjust(4), end = "")
print("\n" + " " * 5 + "+" + "-" * 4 * sloupcu, end = "")
# tabulka znaků
for kod in range(128): # pro ASCII rozsah
    if kod % sloupcu == 0:
        # začátek nového řádku
        print("\n" + str(kod).rjust(4) + " |", end = "")
    # test jednotlivého znaku
    znak = chr(kod)
    if znak.isprintable():
        print(" '" + znak + "'", end = "") # znak v apostrofech
    else:
        print(" ---", end = "") # netisknutelný znak
print()

Za povšimnutí ve výsledné tabulce (kód znaku je součtem hodnoty na začátku řádku a indexem sloupce uvedeným v hlavičce)

                            Tabulka znaků ASCII                       

         0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
     +----------------------------------------------------------------
   0 | --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
  16 | --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
  32 | ' ' '!' '"' '#' '$' '%' '&' ''' '(' ')' '*' '+' ',' '-' '.' '/'
  48 | '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' ':' ';' '<' '=' '>' '?'
  64 | '@' 'A' 'B' 'C' 'D' 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O'
  80 | 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' 'X' 'Y' 'Z' '[' '\' ']' '^' '_'
  96 | '`' 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o'
 112 | 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' 'x' 'y' 'z' '{' '|' '}' '~' ---

stojí několik věcí. Kódy menší než 32 odpovídají netisknutelným řídicím znakům. Prvním běžným znakem je mezera (kód 32). Číslice, velká písmena anglické abecedy a malá písmena anglické abecedy vždy tvoří kompaktní skupinu s očekávaným pořadím6), mezi nimi se však vždy vyskytují další symboly. Malé anglické písmeno má kód vždy o 32 větší než odpovídající velké.

1)
Nemáme žádný zvláštní datový typ pro jeden znak, znak je řetězec délky 1.
2)
někdy se hovoří o řezu
3)
jakkoli logické z hlediska interpretace znaků v počítači
4)
jako součást ještě obecnějšího úkolu, totiž přizpůsobení programů nejrůznějším národním zvyklostem jako formáty data a času, zápis čísel (např.oddělovač desetinné části), měnové údaje a právě řazení řetězců
5)
Vzhledem k tomu, že chyby zatím neumíme v programu zpracovávat, je pro nás v tuto chvíli metoda find vhodnější.
6)
To je pěkná vlastnost, kterou lze občas v programech využít. Jiný způsob kódování EBCDIC, který byl navržen v počátcích počítačového věku a dnes je prakticky zapomenut, tuto výhodu nemá.
prog/string.txt · Poslední úprava: 07.01.2018 16:21 autor: Ivana Stefanová