Lekce 14 - 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 Pythonu 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 | not |
Ř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
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 když porovnáváme
slova v abecedním pořádku. Například "slon" je dle abecedy před
"zebrou".
Řezání
Z řetězců lze stejně jako ze seznamů extrahovat jednotlivé prvky. 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 rozsahum
ažn-1
.seznam[m:n:i]
– Vyberem
a každýi
-tý znak don-1
.
Samozřejmě lze využít i speciality jako [:]
, která vybere
celý řetězec, nebo [::-1]
, která řetězec převrátí. 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ž lze řetězce jednoduše upravovat. Zde si uvedeme metody, 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í podřetězec
nalezen, metoda 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ě metoda 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, metoda 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
po zadání 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 zanalyzuje 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 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 definujeme 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ýznamnější z novobabylonských králů Nabuchodonozor II. vládl v letech 605 až 562 př. n. l.
Vaše věta: "Nejvýznamnější z novobabylonských králů Nabuchodonozor II. vládl v letech 605 až 562 př. n. l." má:
samohlásek: 25
souhlásek: 45
čísel: 6
ostatních znaků: 18
Aplikaci ukončíte stisknutím klávesy Enter...
Zápis samohlasky += 1
je zkrácená verze
samohlasky = samohlasky + 1
. V Pythonu se tento zápis 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 spočívá 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 jsou v ASCII hodnotách 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 Caesarova
šifra. Program si dokonce můžeme už teď vyzkoušet v praxi – Online Caesarova
š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 bojkotovat a budeme
předpokládat, že ji uživatel nebude zadávat. Ideálně bychom poté měli
diakritiku i všechny ostatní znaky kromě písmen před šifrováním
odstranit. 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ě:
# 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:
i = ord(znak)
i = i + posun
znak = chr(i)
zprava = zprava + znak
# Výpis
print("Zašifrovaná zpráva:", zprava)
input()
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 také další ošklivé
znaky. Uzavřeme proto znaky do kruhu tak, aby posun po z
plynule
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
:
# 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:
i = ord(znak)
i = i + posun
# kontrola přetečení
if (i > ord("z")):
i = i - 26
znak = chr(i)
zprava = zprava + znak
# Výpis
print("Zašifrovaná zpráva:", zprava)
input()
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 14. 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 212x (1.88 kB)
Aplikace je včetně zdrojových kódů v jazyce Python