Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 13 - Textové řetězce v Pythonu podruhé - Práce se znaky

V minulé lekci, Nejčastější chyby Python nováčků - Umíš pojmenovat proměnné?, jsme si ukázali nejčastější chyby začátečníků v Python ohledně pojmenování proměnných.

V dnešním Python tutoriálu dále rozšíříme své znalosti řetězců. Naučíme se jejich porovnávání a řezání. Popíšeme si také nejdůležitější metody, které k práci s řetězci budeme často potřebovat.

Porovnávání řetězců

Řetězce se dají porovnávat pomocí standardních operátorů, které už dobře známe z předchozích lekcí:

Operátor Zápis
Rovnost ==
Je ostře větší >
Je ostře menší <
Je větší nebo rovno >=
Je menší nebo rovno <=
Nerovnost !=
Obecná negace !

Řetězce se porovnávají podle abecedy. Přesněji řečeno tak, že se vezmou postupně jednotlivé znaky porovnávaných řetězců a porovnají se pomocí funkce ord(). Tudíž znak a je menší než b, jelikož číselná hodnota a je 97 a číselná hodnota b je 98. Podívejme se na příklady:

print("a" < "b")
print("b" < "a")
print("c" == "c")
print("ab" >= "a")
print("e" <= "df")
print("java" == "javascript")
print("python" != "php")

Řetězce se v Pythonu porovnávají znak po znaku zleva doprava. Takže i když je ve výrazu "e" <= "df" písmeno f je větší než e, Python se na f ani nedívá, protože už našel rozdíl mezi prvními znaky řetězců (e a d). Je to podobné, jako bychom porovnávali slova v abecedním pořádku. Například "slon" je dle abecedy před "zebrou".

Řezání

Ze řetězců lze extrahovat jednotlivé prvky stejně jako ze seznamů. K tomuto účelu se používají hranaté závorky. Syntaxe je totožná jako u seznamů. Platí, že řetězec můžeme chápat jako seznam znaků:

  • seznam[m] - vybere jediný znak
  • seznam[m:n] - vybere znaky v rozsahu mn-1
  • seznam[m:n:i] - vybere m a každý i-tý znak do n-1

Samozřejmě lze využít i speciality jako [:] - vybere celý řetězec, nebo [::-1] - převrátí řetězec. Ukažme si příklad řezání řetězce:

retezec = "Honolulu"
print(retezec[0])
print(retezec[1:4])
print(retezec[::2])
print(retezec[3:9:2])

V konzoli uvidíme výstup:

Výstup řezání řetězce:
H
ono
Hnll
ouu

Metody pro práci s řetězci

Řetězce na sobě mají mnoho užitečných metod, díky nimž je lze jednoduše upravovat. Zde si uvedeme ty, které se využívají velmi často. Nejprve ale malé upřesnění. S funkcemi i metodami jsme se již setkali.

Rozdíl mezi nimi je ten, že funkce (mimo těch, které se později naučíme psát sami) jsou součástí programového jádra Pythonu. Metoda je pak funkce definovaná uvnitř třídy a volaná pro objekt.

Objekty se budeme zabývat dále v kurzu Objektově orientovaného programování v Pythonu.

Metoda count()

Metoda vrátí počet podřetězců v jiném řetězci. Parametrem je hledaný podřetězec:

retezec = "alabama"
print(retezec.count("a"))
print(retezec.count("a", 1, 4)) # Totéž jako retezec[1:4].count("a")

Metoda find()

Metoda nám vrátí index první pozice podřetězce v jiném řetězci. Hledaný podřetězec předáváme jako parametr. Pokud není nalezen, vrátí -1:

retezec = "Wolfgang Amadeus Mozart"
print(retezec.find("Wolfgang"))
print(retezec.find("Beethoven"))

Metoda index()

Tato metoda je velmi podobná předchozí metodě find(), avšak pokud podřetězec nenalezne, vyvolá výjimku:

retezec = "Wolfgang Amadeus Mozart"
print(retezec.index("Wolfgang"))
try:
    print(retezec.index("Beethoven"))
except ValueError:
    print("Podřetězec nebyl nalezen!")

Konstrukce try: - except: slouží v Pythonu k zachycení výjimky. Více se tématu budeme věnovat dále v kurzu.

Metoda isalpha()

Metoda nám vrátí hodnotu True, pokud jsou všechny znaky v řetězci písmenné znaky a řetězec obsahuje minimálně jeden znak. V opačném případě vrátí False:

prvni_retezec = "Airbus"
print(prvni_retezec.isalpha())
druhy_retezec = "Boeing 737"
print(druhy_retezec.isalpha())

Metoda isdigit()

Tato metoda vrátí True, pokud jsou všechny znaky v řetězci číselné znaky (0 - 9) a řetězec obsahuje minimálně jeden znak. Pokud tato podmínka není splněna, vrátí False:

prvni_retezec = "123"
print(prvni_retezec.isdigit())
druhy_retezec = "boeing737"
print(druhy_retezec.isdigit())

Metoda islower()

Metoda vrátí True, pokud jsou všechny znaky v řetězci malá písmena a řetězec obsahuje minimálně jeden znak:

prvni_retezec = "arizona"
print(prvni_retezec.islower())
druhy_retezec = "AriZona"
print(druhy_retezec.islower())

Metoda isupper()

Metoda vrátí True, pokud jsou všechny znaky v řetězci velká písmena a řetězec obsahuje minimálně jeden znak:

prvni_retezec = "ARIZONA"
print(prvni_retezec.isupper())
druhy_retezec = "arizona"
print(druhy_retezec.isupper())

Další metody pro práci s řetězci si můžeme prohlédnout zadáním příkazu help(str) v konzoli.

Využití znalostí práce s řetězci v praxi

O řetězcích už víme poměrně dost. Pojďme si tedy naše znalosti vyzkoušet v praxi na třech zajímavých programech.

Analýza výskytu znaků ve větě

Napišme si jednoduchý program, který nám analyzuje zadanou větu. Bude nás zajímat počet samohlásek, souhlásek a počet nepísmenných znaků (např. mezera nebo !).

Řetězec budeme projíždět cyklem po jednom znaku. Neapelujeme na rychlost programu a budeme volit názorná a jednoduchá řešení.

Protože se jedná o složitější kód, nebudeme zapomínat na komentáře.

Nejprve si od uživatele získáme vstupní řetězec, který budeme analyzovat. Abychom nemuseli řešit velikost písmen, celý řetězec na začátku převedeme na malá písmena. Připravíme si proměnné s výchozími hodnotami a definujme si samohlásky, souhlásky a čísla. Počet ostatních znaků pak bude vše, co zbude. V hlavním cyklu budeme větu procházet znak po znaku. Pokaždé rozhodneme, do které kategorie znak patří. Podle toho pak budeme ukládat jednotlivé počty do odpovídajících proměnných:

print("Program zjistí, z čeho se skládá věta.")
zadana_veta = input("Zadejte větu: ")

# Převedeme větu na malá písmena. Původní větu si ponecháme v proměnné zadana_veta beze změny
veta = zadana_veta.lower()

#  Nastavíme výchozí počty proměnných
samohlasky = 0
souhlasky = 0
ostatni = 0
cisel = 0

#  Definujeme sady typů znaků
samohlasky_sada = "aáeéěiíoóuúůyý"
souhlasky_sada = "bcčdďfghjklmnňpqrřsštťvwxzž"
cisla_sada = "0123456789"

#  V hlavním cyklu programu analyzujeme druh a počet znaků
for znak in veta:
    if znak in samohlasky_sada:      # Nejprve samohlásky
        samohlasky += 1
    elif znak in souhlasky_sada:     # Pak souhlásky
        souhlasky += 1
    elif znak in cisla_sada:         # Poté čísla
        cisel += 1
    else:
        ostatni += 1        # Vše, co zbylo, jsou ostatní znaky (mezery, tečky atd...)

# Zde využijeme původní nezměněnou větu
print(f'Vaše věta: "{zadana_veta}" má:')
print("samohlásek:", samohlasky)
print("souhlásek:", souhlasky)
print("čísel:", cisel)
print("ostatních znaků:", ostatni)

input("\nAplikaci ukončíte stisknutím klávesy Enter...")

Výstup programu:

Výstup programu analýzy věty:
Program zjistí, z čeho se skládá věta.
Zadejte větu: Nejvýznmamnější z novobabylonských králů Nabuchodonozor II. vládl v letech 605 až 562 př. n. l.
Vaše věta: "Nejvýznmamnější z novobabylonských králů Nabuchodonozor II. vládl v letech 605 až 562 př. n. l." má:
samohlásek: 25
souhlásek: 46
čísel: 6
ostatních znaků: 18

Aplikaci ukončíte stisknutím klávesy Enter...

Zápis samohlasky += 1 je zkrácená verze samohlasky = samohlásky + 1. V Pythonu se používá naprosto běžně ke zkrácení operací s proměnnými. Analogicky funguje i s ostatními operátory (např. -=, *=, /= atd.).

ASCII hodnota

Nyní se blíže podíváme na ASCII tabulku. Zejména v éře operačního systému MS-DOS prakticky nebyla jiná možnost, jak zaznamenávat text. Jednotlivé znaky byly uloženy jako čísla typu byte, tedy s rozsahem hodnot od 0 do 255. V systému byla uložena tzv. ASCII tabulka, která měla 256 znaků a každému ASCII kódu (číselnému kódu) přiřazovala jeden znak.

Tento způsob neměl šanci přetrvat dodnes. Do tabulky se jednoduše nevejdou všechny znaky všech národních abeced. Nyní se používá Unicode (UTF-8) kódování, kde jsou znaky reprezentovány trochu jiným způsobem. V Pythonu přesto máme možnost pracovat s ASCII hodnotami jednotlivých znaků. Hlavní výhoda je v tom, že znaky jsou uloženy v tabulce za sebou podle abecedy. Například na pozici 97 nalezneme 'a', na 98 zase 'b' a podobně. Stejné je to s čísly. Diakritické znaky tam jsou bohužel jen nějak rozházené.

Zkusme si nyní převést znak do jeho ASCII hodnoty a naopak podle ASCII hodnoty daný znak vytvořit:

print(ord("a"))
print(chr(97))

V konzoli uvidíme výstup:

Převod znaku na ASCII a zpět:
97
a

K získání ordinální (ASCII) hodnoty znaku jsme použili funkci ord(). Pomocí funkce chr() jsme naopak získali znak z jeho ordinální hodnoty.

Caesarova šifra

Vytvoříme si jednoduchý program pro šifrování textu. Pokud jste někdy slyšeli o Caesarově šifře, bude to přesně to, co si zde naprogramujeme. Šifrování textu spočívá v posouvání znaku v abecedě o určitý, pevně stanovený, počet znaků. Například slovo ahoj se s posunem textu o 1 přeloží jako bipk. Posun umožníme uživateli vybrat. Algoritmus máme detailně vysvětlený v článku Césarova šifra. Program si dokonce můžeme už teď vyzkoušet v praxi - Online Césarova šifra.

Vraťme se ale k programování a připravme si kód. Budeme potřebovat proměnné pro původní text, pro zašifrovanou zprávu a pro posun. Dále budeme potřebovat vytvořit cyklus procházející jednotlivé znaky a cyklus pro výpis zašifrované zprávy. Zprávu si nejprve necháme zapsanou napevno v kódu, abychom ji nemuseli při každém spuštění programu psát znovu. Po dokončení nahradíme obsah proměnné funkcí input(). Šifra nepočítá s diakritikou, mezerami a interpunkčními znaménky. Diakritiku budeme bojkovat :-) a budeme předpokládat, že ji uživatel nebude zadávat. Ideálně bychom poté měli diakritiku před šifrováním odstranit, stejně tak všechny ostatní znaky kromě písmen. Pojďme na to:

# Inicializace proměnných
retezec = "gaiusjuliuscaesar"
print("Původní zpráva:", retezec)
zprava = ""
posun = 1

# Cyklus projíždějící jednotlivé znaky
for znak in retezec:
    pass         # Klíčové slovo pass se v Pythonu používá mj. pro prozatímně prázdný cyklus. Více se o něm dovíme později v kurzu.
# Výpis
print("Zašifrovaná zpráva:", zprava)
input()

Nyní se přesuneme dovnitř cyklu. V něm převedeme znak na ASCII hodnotu (neboli ordinální hodnotu). Tuto hodnotu zvýšíme o posun a převedeme zpět na znak. Tento znak nakonec připojíme k výsledné zprávě:

# Cyklus projíždějící jednotlivé znaky
for znak in retezec:
    i = ord(znak)
    i = i + posun
    znak = chr(i)
    zprava = zprava + znak

Program si vyzkoušíme. Výsledek v konzoli vypadá docela dobře:

Caesarova šifra:
Původní zpráva: gaiusjuliuscaesar
Zašifrovaná zpráva: hbjvtkvmjvtdbftbs

Zkusme si však zadat vyšší posun nebo napsat slovo zebra. Vidíme, že znaky mohou po z přetéct do ASCII hodnot dalších znaků, v textu tedy již nemáme jen písmena, ale další ošklivé znaky. Uzavřeme znaky do kruhu tak, aby posun plynule po z přešel opět k a a dále. Postačí nám k tomu jednoduchá podmínka, která od nové ASCII hodnoty odečte celou abecedu tak, abychom začínali opět na a:

    i = ord(znak)
    i = i + posun
    # kontrola přetečení
    if (i > ord("z")):
        i = i - 26
    znak = chr(i)
    zprava = zprava + znak

V konzoli vidíme, že naše úprava funguje správně:

Caesarova šifra:
Původní zpráva: gaiusjuliuscaesar
Zašifrovaná zpráva: hbjvtkvmjvtdbftbs

Pokud i přesáhne ASCII hodnotu z, snížíme ho o 26 znaků (tolik znaků má anglická abeceda). Je to jednoduché a náš program je nyní funkční. Všimněme si, že nikde nepoužíváme přímé kódy znaků, v podmínce je ord("z"), i když bychom tam mohli napsat rovnou 122. Je to z důvodu, aby byl náš program plně odstíněn od explicitních ASCII hodnot a bylo lépe viditelné, jak funguje. Cvičně si zkuste udělat dešifrování :)

V následujícím cvičení, Řešené úlohy k 13. lekci Pythonu, si procvičíme nabyté zkušenosti z předchozích lekcí.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 63x (1.88 kB)
Aplikace je včetně zdrojových kódů v jazyce Python

 

Předchozí článek
Nejčastější chyby Python nováčků - Umíš pojmenovat proměnné?
Všechny články v sekci
Základní konstrukce jazyka Python
Přeskočit článek
(nedoporučujeme)
Řešené úlohy k 13. lekci Pythonu
Článek pro vás napsal gcx11
Avatar
Uživatelské hodnocení:
657 hlasů
(^_^)
Aktivity