13. diel - Textové reťazce v Pythone druhýkrát - Práca so znakmi
V minulej lekcii, Časté chyby Python nováčikov - Vieš pomenovať premenné?, sme si ukázali najčastejšie chyby začiatočníkov v Pythone ohľadom pomenovania premenných.
V dnešnom Python tutoriále ďalej rozšírime svoje znalosti reťazcov. Naučíme sa ich porovnávanie a rezanie. Popíšeme si tiež najdôležitejšie metódy, ktoré na prácu s reťazcami budeme často potrebovať.
Porovnávanie reťazcov
Reťazce sa dajú porovnávať pomocou štandardných operátorov, ktoré už dobre poznáme z predchádzajúcich lekcií:
Operátor | Zápis |
---|---|
Rovnosť | == |
Je ostro väčšia | > |
Je ostro menší | < |
Je väčšia alebo rovná | >= |
Je menšia alebo rovná | <= |
Nerovnosť | != |
Všeobecná negácia | not |
Reťazce sa porovnávajú podľa abecedy. Presnejšie povedané tak, že sa
vezmú postupne jednotlivé znaky porovnávaných reťazcov a porovnajú sa
pomocou funkcie ord()
. Preto znak a
je menší ako
b
, pretože číselná hodnota a
je 97
a
číselná hodnota b
je 98
. Pozrime sa na
príklady:
print("a" < "b")
print("b" < "a")
print("c" == "c")
print("ab" >= "a")
print("e" <= "df")
print("java" == "javascript")
print("python" != "php")
Reťazce sa v Pythone porovnávajú znak po znaku zľava
doprava. Takže aj keď je vo výraze "e" <= "df"
písmeno
f
väčšie ako e
, Python sa na f
ani
nepozerá, pretože už našiel rozdiel medzi prvými znakmi reťazcov
(e
a d
). Je to podobné, ako keď porovnávame slová
v abecednom poriadku. Napríklad "slon" je podľa abecedy pred "zebrou".
Rezanie
Z reťazcov je možné rovnako ako zo zoznamov extrahovať jednotlivé prvky. Na tento účel sa používajú hranaté zátvorky. Syntax je totožná ako pri zoznamoch. Platí, že reťazec môžeme chápať ako zoznam znakov:
list[m]
– Vyberie jediný znak.list[m:n]
– Vyberie znaky v rozsahum
ažn-1
.list[m:n:i]
– Vyberiem
a každýi
-tý znak don-1
.
Samozrejme je možné využiť aj špeciality ako [:]
, ktorá
vyberie celý reťazec, alebo [::-1]
, ktorá reťazec prevráti.
Ukážme si príklad rezania reťazca:
string = "Honolulu"
print(string[0])
print(string[1:4])
print(string[::2])
print(string[3:9:2])
V konzole uvidíme výstup:
String slicing output:
H
ono
Hnll
ouu
Metódy pre prácu s reťazcami
Reťazce na sebe majú mnoho užitočných metód, vďaka ktorým je možné reťazce jednoducho upravovať. Tu si uvedieme metódy, ktoré sa využívajú veľmi často. Najprv ale malé upresnenie. S funkciami aj metódami sme sa už stretli.
Rozdiel medzi nimi je ten, že funkcie (okrem tých, ktoré sa neskôr naučíme písať sami) sú súčasťou programového jadra Pythona. Metóda je potom funkcia definovaná vo vnútri triedy a volaná pre objekt.
Objekty sa budeme zaoberať ďalej v kurze Objektovo orientovaného programovania v Pythone.
Metóda count()
Metóda vráti počet podreťazcov v inom reťazci. Parametrom je hľadaný podreťazec:
string = "alabama"
print(string.count("a"))
print(string.count("a", 1, 4)) # The same as string[1:4].count("a")
Metóda find()
Metóda nám vráti index prvej pozície podreťazca v inom reťazci.
Hľadaný podreťazec odovzdávame ako parameter. Ak nie je podreťazec
nájdený, metóda vráti -1
:
string = "Wolfgang Amadeus Mozart"
print(string.find("Wolfgang"))
print(string.find("Beethoven"))
Metóda index()
Táto metóda je veľmi podobná predchádzajúcej metóde
find()
, avšak pokiaľ podreťazec nenájde, vyvolá výnimku:
string = "Wolfgang Amadeus Mozart"
print(string.index("Wolfgang"))
try:
print(string.index("Beethoven"))
except ValueError:
print("Substring not found!")
Konštrukcia try:
– except:
slúži
v Pythone na zachytenie výnimky. Viac sa téme budeme venovať ďalej v
kurze.
Metóda isalpha()
Metóda nám vráti hodnotu True
, ak sú všetky znaky v
reťazci písmenné znaky a reťazec obsahuje minimálne jeden znak. V opačnom
prípade metóda vráti False
:
first_string = "Airbus"
print(first_string.isalpha())
second_string = "Boeing 737"
print(second_string.isalpha())
Metóda isdigit()
Táto metóda vráti True
, ak sú všetky znaky v reťazci
číselné znaky (0
– 9
) a reťazec obsahuje
minimálne jeden znak. Ak táto podmienka nie je splnená, metóda vráti
False
:
first_string = "123"
print(first_string.isdigit())
second_string = "boeing737"
print(second_string.isdigit())
Metóda islower()
Metóda vráti True
, ak sú všetky znaky v reťazci malé
písmená a reťazec obsahuje minimálne jeden znak:
first_string = "arizona"
print(first_string.islower())
second_string = "AriZona"
print(second_string.islower())
Metóda isupper()
Metóda vráti True
, ak sú všetky znaky v reťazci veľké
písmená a reťazec obsahuje minimálne jeden znak:
first_string = "ARIZONA"
print(first_string.isupper())
second_string = "arizona"
print(second_string.isupper())
Ďalšie metódy pre prácu s reťazcami si môžeme prezrieť
po zadaní príkazu help(str)
v konzole.
Využitie znalostí práce s reťazcami v praxi
O reťazcoch už vieme pomerne dosť. Poďme si teda naše znalosti vyskúšať v praxi na troch zaujímavých programoch.
Analýza výskytu znakov vo vete
Napíšme si jednoduchý program, ktorý nám zanalyzuje zadanú vetu. Bude
nás zaujímať počet samohlások, spoluhlások a počet nepísmenných znakov
(napr. medzera alebo !
).
Reťazec budeme prechádzať cyklom po jednom znaku. Neapelujeme na rýchlosť programu a budeme voliť názorné a jednoduché riešenia.
Pretože sa jedná o zložitejší kód, nebudeme zabúdať na komentáre.
Najprv od používateľa získame vstupný reťazec, ktorý budeme analyzovať. Aby sme nemuseli riešiť veľkosť písmen, celý reťazec na začiatku prevedieme na malé písmená. Pripravíme si premenné s východiskovými hodnotami a definujeme si samohlásky, spoluhlásky a čísla. Počet ostatných znakov potom bude všetko, čo zostane. V hlavnom cykle budeme vetu prechádzať znak po znaku. Zakaždým rozhodneme, do ktorej kategórie znak patrí. Podľa toho potom budeme ukladať jednotlivé počty do zodpovedajúcich premenných:
print("The program will determine what the sentence consists of.")
entered_sentence = input("Enter a sentence: ")
# Convert the sentence to lowercase. The original sentence is kept in the variable entered_sentence without changes.
sentence = entered_sentence.lower()
# Set the default counts for the variables
vowels = 0
consonants = 0
others = 0
numbers = 0
# Define sets of character types
vowels_set = "aáeéěiíoóuúůyý"
consonants_set = "bcčdďfghjklmnňpqrřsštťvwxzž"
numbers_set = "0123456789"
# In the main loop of the program, analyze the type and count of characters
for character in sentence:
if character in vowels_set: # First vowels
vowels += 1
elif character in consonants_set: # Then consonants
consonants += 1
elif character in numbers_set: # Then numbers
numbers += 1
else:
others += 1 # Everything else is other characters (spaces, dots, etc.)
# Here we use the original unchanged sentence
print(f'Your sentence: "{entered_sentence}" contains:')
print("vowels:", vowels)
print("consonants:", consonants)
print("numbers:", numbers)
print("other characters:", others)
input("\nPress Enter to close the application...")
Výstup programu:
Sentence analysis program output:
The program will determine what the sentence consists of.
Enter a sentence: The most significant of the Neo-Babylonian kings, Nebuchadnezzar II, reigned from 605 to 562 BC.
Your sentence: "The most significant of the Neo-Babylonian kings, Nebuchadnezzar II, reigned from 605 to 562 BC." contains:
vowels: 28
consonants: 44
numbers: 6
other characters: 18
Press Enter to close the application...
Zápis vowels += 1
je skrátená verzia
vowels = vowels + 1
. V Pythone sa tento zápis používa úplne
bežne na skrátenie operácií s premennými. Analogicky funguje aj s
ostatnými operátormi (napr. -=
, *=
, /=
atď.).
ASCII hodnota
Teraz sa bližšie pozrieme na ASCII tabuľku. Najmä v ére
operačného systému MS-DOS prakticky nebola iná možnosť,
ako zaznamenávať text. Jednotlivé znaky boli uložené ako čísla typu
byte
, teda s rozsahom hodnôt od 0
do
255
. V systéme bola uložená tzv. ASCII tabuľka, ktorá mala 256
znakov a každému ASCII kódu (číselnému kódu) priraďovala jeden znak.
Tento spôsob nemal šancu pretrvať dodnes. Do tabuľky sa jednoducho
nezmestia všetky znaky všetkých národných abecied. Teraz sa používa
Unicode (UTF-8) kódovanie, kde sú znaky reprezentované trochu iným
spôsobom. V Pythone napriek tomu máme možnosť pracovať s ASCII hodnotami
jednotlivých znakov. Hlavná výhoda spočíva v tom, že znaky sú uložené v
tabuľke za sebou podľa abecedy. Napríklad na pozícii 97
nájdeme 'a'
, na 98
zase 'b'
a podobne.
Rovnaké je to s číslami. Diakritické znaky sú v ASCII hodnotách bohužiaľ
len nejako rozhádzané.
Skúsme si teraz previesť znak do jeho ASCII hodnoty a naopak podľa ASCII hodnoty daný znak vytvoriť:
print(ord("a"))
print(chr(97))
V konzole uvidíme výstup:
Converting a character to ASCII and back:
97
a
Na získanie ordinálnej (ASCII) hodnoty znaku sme použili funkciu
ord()
. Pomocou funkcie chr()
sme naopak získali znak
z jeho ordinálnej hodnoty.
Caesarova šifra
Vytvoríme si jednoduchý program na šifrovanie textu. Ak ste niekedy
počuli o Caesarovej šifre, bude to presne to, čo si tu naprogramujeme.
Šifrovanie textu spočíva v posúvaní znaku v abecede o určitý, pevne
stanovený počet znakov. Napríklad slovo hello
sa s posunom textu
o 1
preloží ako ifmmp
. Posun umožníme
užívateľovi vybrať. Algoritmus máme detailne vysvetlený v článku Caesarovho
šifra. Program si dokonca môžeme už teraz vyskúšať v praxi - Online Caesarovho
šifra.
Vráťme sa ale na programovanie a pripravme si kód. Budeme potrebovať
premenné pre pôvodný text, pre zašifrovanú správu a pre posun. Ďalej
budeme potrebovať vytvoriť cyklus prechádzajúci jednotlivé znaky a cyklus
pre výpis zašifrovanej správy. Správu si najskôr necháme zapísanú
napevno v kóde, aby sme ju nemuseli pri každom spustení programu písať
znova. Po dokončení nahradíme obsah premennej funkcií input()
.
Šifra nepočíta s diakritikou, medzerami a interpunkčnými znamienkami.
Diakritiku budeme bojkotovať
a budeme predpokladať, že ju užívateľ nebude zadávať. Ideálne by sme
potom mali diakritiku aj všetky ostatné znaky okrem písmen pred šifrovaním
odstrániť. Poďme na to:
# Variable initialization original_message = "gaiusjuliuscaesar" print("Original message:", original_message) encrypted_message = "" shift = 1 # Loop iterating over characters for character in original_message: pass # The pass keyword in Python is used, among other things, for a temporarily empty loop. We will learn more about it later in the course. # Printing print("Encrypted message:", encrypted_message) input()
Teraz sa presunieme dovnútra cyklu. V ňom prevedieme character
na ASCII hodnotu (čiže ordinálnu hodnotu). Túto hodnotu zvýšime o
shift
a prevedieme späť na znak. Tento znak nakoniec pripojíme k
výslednej správe:
# Variable initialization
original_message = "gaiusjuliuscaesar"
print("Original message:", original_message)
encrypted_message = ""
shift = 1
# loop iterating over characters
for character in original_message:
i = ord(character)
i = i + shift
character = chr(i)
encrypted_message = encrypted_message + character
# Printing
print("Encrypted message:", encrypted_message)
input()
Program si vyskúšame. Výsledok v konzole vyzerá celkom dobre:
Caesar cipher:
Original message: gaiusjuliuscaesar
Encrypted message: hbjvtkvmjvtdbftbs
Skúsme si však zadať vyšší posun alebo napísať slovo
zebra
. Vidíme, že znaky môžu po z
pretiecť do
ASCII hodnôt ďalších znakov, v texte teda už nemáme len písmená, ale aj
ďalšie škaredé znaky. Uzavrieme preto znaky do kruhu tak, aby posun po
z
plynule prešiel opäť k a
a ďalej. Postačí nám
k tomu jednoduchá podmienka, ktorá od novej ASCII hodnoty odpočíta celú
abecedu tak, aby sme začínali opäť na a
:
# Variable initialization
original_message = "gaiusjuliuscaesar"
print("Original message:", original_message)
encrypted_message = ""
shift = 1
# loop iterating over characters
for character in original_message:
i = ord(character)
i = i + shift
# overflow control
if (i > ord("z")):
i = i - 26
character = chr(i)
encrypted_message = encrypted_message + character
# Printing
print("Encrypted message:", encrypted_message)
input()
V konzole vidíme, že naša úprava funguje správne:
Caesar Cipher:
Original message: gaiusjuliuscaesar
Encrypted message: hbjvtkvmjvtdbftbs
Pokiaľ i
presiahne ASCII hodnotu z
, znížime ho o
26
znakov (toľko znakov má anglická abeceda). Je to jednoduché
a náš program je teraz funkčný. Všimnime si, že nikde nepoužívame priame
kódy znakov. V podmienke je ord("z")
, aj keď by sme tam mohli
napísať rovno 122
. Je to z dôvodu, aby bol náš program plne
odtienený od explicitných ASCII hodnôt a bolo lepšie viditeľné, ako
funguje. Cvične si skúste urobiť dešifrovanie
V nasledujúcom cvičení, Riešené úlohy k 13. lekcii Pythonu, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 0x (2.14 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Python