IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

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 rozsahu mn-1.
  • list[m:n:i] – Vyberie m a každý i-tý znak do n-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 (09) 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:

# loop iterating over characters
for character in original_message:
    i = ord(character)
    i = i + shift
    character = chr(i)
    encrypted_message = encrypted_message + character

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:

    i = ord(character)
    i = i + shift
    # overflow control
    if (i > ord("z")):
        i = i - 26
    character = chr(i)
    encrypted_message = encrypted_message + character

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

 

Predchádzajúci článok
Časté chyby Python nováčikov - Vieš pomenovať premenné?
Všetky články v sekcii
Základná konštrukcia jazyka Python
Preskočiť článok
(neodporúčame)
Riešené úlohy k 13. lekcii Pythonu
Článok pre vás napísal gcx11
Avatar
Užívateľské hodnotenie:
9 hlasov
(^_^)
Aktivity