Cvičení č. 14 rozšířené o poznámky ze cvičení a řešení některých příkladů (ZS 2024/25)¶

V minulém díle jste viděli…¶

Textový řetězec (string) je základní datový typ v Pythonu, který představuje posloupnost libovolných znaků. Se stringy pracujeme pomocí typu str, což je neměnný (immutable) kontejner.

Stringy zapisujeme pomocí jednoduchých nebo dvojitých uvozovek, případně pomocí trojic jednoduchých nebo dvojitých uvozovek.

In [1]:
s1 = "Potřebuji 'apostrofy'"
s2 = 'Potřebuji "uvozovky"'
s3 = '''Jsem víceřádkový string,
vytvořený pomocí
trojic jednoduchých uvozovek.'''
print(s1)
print(s2)
print(s3)
Potřebuji 'apostrofy'
Potřebuji "uvozovky"
Jsem víceřádkový string,
vytvořený pomocí
trojic jednoduchých uvozovek.

Použití escape sekvencí začínajících zpětným lomítkem (\) umožňuje vkládat do stringů speciální znaky, jako například nový řádek (\n) nebo uvozovky (\").

Python umožňuje převádět stringy na jiné datové typy a zpět.

In [2]:
print(int("1234"))
print(float(-3.5))
print(complex("1+2j"))
print(bool("0"))
print(str("Python"))
print(repr("Python"))
1234
-3.5
(1+2j)
True
Python
'Python'
In [7]:
# opakovani:
s = "abcdef ahoj!"

# podmínka
c = "a"
if c in s:
    print("ano, je tam")  

# for-cyklus:
for x in s:
    print(x, end = " ")
print("")

for i in range(len(s)):
    print(s[i], end = " ")
print("")

# indexace:
print(s[0])
#s[0] = "2" # chyba!

# slicing
print(s[2:4])

# zřetězení
s = "ahoj" + " " + "lidi"
print(s)
s = "20" * 3 + " " + s[1:-3]
s += " A"
print(s)
ano, je tam
a b c d e f   a h o j ! 
a b c d e f   a h o j ! 
a
cd
ahoj lidi
202020 hoj l A

Pro stringy je možné používat základní operace jako testování, iterování, zřetězení, porovnání. Dále je k dispozici indexování a slicing. Porovnávání stringů se provádí znak po znaku podle jejich kódů. Pozor na výsledky porovnání, které mohou být ovlivněny znakovou sadou a velikostí písmen!

Pro zpracování jednotlivých znaků lze použít funkce chr() a ord(). Funkce chr(i) převádí celé číslo i na znak, zatímco ord(c) převádí znak c na jeho kód v Unicode. Python nezavádí samostatný datový typ pro znaky, zadávají se jako stringy obsahující pouze jeden znak.

In [9]:
print(chr(0x20ac))    # Znak euro
print(chr(87))
print(ord("€"))

# porovnání:

print("a" < "A")   # False
print(ord("a"), ord("A"), ord("Á"))

print(sorted("abhjsHWUVPgcvsdgcdsjkzdg"))
€
W
8364
False
97 65 193
['H', 'P', 'U', 'V', 'W', 'a', 'b', 'c', 'c', 'd', 'd', 'd', 'g', 'g', 'g', 'h', 'j', 'j', 'k', 's', 's', 's', 'v', 'z']

Textové řetězce (2. část)¶

Metody pro práci se stringy¶

Typ str v Pythonu poskytuje řadu metod pro běžné operace s textem. Podrobně se s pojmem metoda seznámíme na konci semestru v tématu o objektově orientovaném programování, ale již při používání jiných typů jsme se s metodami setkali (např. komplexní čísla – metoda complex.conjugate() nebo seznamy – metoda list.append()).

Pro připomenutí: metoda je "v podstatě funkce", která provádí akci spojenou s konkrétním objektem. Při volání metody pro string budeme používat obecnou syntaxi textový_řetězec.název_metody(), kde textový_řetězec je určitý objekt typu str a název_metody je určitá metoda, kterou chceme použít. V kulatých závorkách při volání metody navíc můžou být parametry, které daná metoda podporuje.

Řetězcových metod je celá řada. Tyto metody můžeme klasifikovat dle účelu, ke kterému slouží:

  • spojování a rozdělování
  • ořezávání
  • vyhledávání
  • nahrazování
  • zjišťovací metody
  • formátování

Některé z nich dále probereme podrobně a ukážeme základní příklady jejich použití. Detaily o všech metodách třídy str jsou k dispozici v dokumentaci https://docs.python.org/3/library/stdtypes.html#string-methods.

Poznámka: Stringy jsou nemodifikovatelná posloupnost, proto žádná z metod typu str nemodifikuje přímo objekt, na kterém je volána. Místo toho je "modifikace" stringu vrácena jako nový objekt. Proto například pokud chceme v proměnné text nahradit všechny výskyty znaku A znakem B, musíme napsat text = text.replace("A", "B") a ne jen text.replace("A", "B"). Pamatujte na to při používání všech metod.

In [10]:
s = [1, 2, 3, 4, 5]
v = s.remove(3)
print(s)
print(v)
[1, 2, 4, 5]
None
In [12]:
s = "abcdefabc"
v = s.replace("a", "")
print(s)
print(v)
abcdefabc
bcdefbc

Spojování a rozdělování stringů¶

Spojení dvou stringů můžeme provést pomocí operátoru +. Pro zřetězení více stringů můžeme místo cyklu použít metodu join (string.join(container)):

  • String, na kterém metodu voláme, funguje jako oddělovač.
  • Kontejner, který předáme metodě jako argument, obsahuje objekty, které chceme spojit.
  • Návratovou hodnotou metody je výsledný zřetězený string.
In [14]:
ovoce = ["Jablko", "Hruška", "Meruňka"]
s1 = ", ".join(ovoce)       # Jako oddělovač použijeme čárku s mezerou
s2 = "".join(ovoce)         # Jako oddělovač použijeme prázdný řetězec
s3 = "; ".join("Jablko")    # Pokud jako argument použijeme string, oddělovač se vloží mezi všechny jeho znaky
s3 = " ".join("Jablko")
print(s1)
print(s2)
print(s3)
Jablko, Hruška, Meruňka
JablkoHruškaMeruňka
J a b l k o

Pokud naopak chceme string rozdělit na části podle určitého oddělovače, můžeme použít některou z následujících metod:

  • split (str.split(sep=None, maxsplit=-1)) – výsledkem je seznam stringů, přičemž každý je částí původního stringu v odpovídajícím pořadí a oddělovače ve výsledném seznamu chybí
    • parametr sep určuje oddělovač (separator) – pokud není zadaný, dělí se dle všech bílých znaků (např. mezera nebo \n)
    • parametr maxsplit určuje, jaký maximální počet dělení se má provést (hodnota -1 znamená bez limitu)
  • rsplit (str.rsplit(sep=None, maxsplit=-1)) – funguje stejně jako split, ale prohledává řetězec od konce
  • splitlines (str.splitlines(keepends=False)) – rozdělí string na jednotlivé řádky (oddělovačem je znak \n) a vrátí seznam stringů, přičemž každý string buď obsahuje konec řádku (pokud keepends=True) nebo neobsahuje konec řádku (pokud keepends=False)
In [5]:
list1 = "Jablko a hruška a meruňka".split(" a ")
list2 = "Jablko,,hruška,,meruňka".split(",")           # Separátory se neslučují
list3 = "Jablko a  hruška\na   meruňka".split()        # Používají se výchozí hodnoty parametrů
list4 = "Jablko,,hruška,,meruňka".split(";")           # Separátor není nalezen
list5 = "Jablko a hruška a meruňka".split(" a ", 1)    # Určujeme maximální počet použití separátoru
list6 = "Jablko a hruška a meruňka".rsplit(" a ", 1)   # Začínáme zprava
print(list1, list2, list3, list4, list5, list6, sep="\n")
['Jablko', 'hruška', 'meruňka']
['Jablko', '', 'hruška', '', 'meruňka']
['Jablko', 'a', 'hruška', 'a', 'meruňka']
['Jablko,,hruška,,meruňka']
['Jablko', 'hruška a meruňka']
['Jablko a hruška', 'meruňka']
In [16]:
"ahoj    lidi\t jablko\n\n\nhruska".split()
Out[16]:
['ahoj', 'lidi', 'jablko', 'hruska']
In [18]:
"ahoj    lidi\t jablko\n\n\nhruska".splitlines(keepends=True)
Out[18]:
['ahoj    lidi\t jablko\n', '\n', '\n', 'hruska']
  • partition (str.partition(sep))
    • pokud string obsahuje zadaný oddělovač (parametr sep), vrátí trojici obsahující string před oddělovačem, oddělovač, a string za oddělovačem
    • pokud string neobsahuje zadaný oddělovač, vrátí trojici obsahující původní string a dva prázdné stringy
  • rpartition (str.rpartition(sep))
    • pokud string obsahuje zadaný oddělovač (parametr sep), vrátí trojici obsahující string před oddělovačem, oddělovač, a string za oddělovačem
    • pokud string neobsahuje zadaný oddělovač, vrátí trojici obsahující dva prázdné stringy a původní string
In [6]:
ntice1 = "Jablko a hruška a meruňka".partition(" a ")
ntice2 = "Jablko a hruška a meruňka".partition(" x ")    # Oddělovač není nalezen
ntice3 = "Jablko a hruška a meruňka".rpartition(" a ")   # Hledáme oddělovač zprava
ntice4 = "Jablko a hruška a meruňka".rpartition(" x ")   # Hledáme zprava, oddělovač není nalezen
print(ntice1, ntice2, ntice3, ntice4, sep="\n")
('Jablko', ' a ', 'hruška a meruňka')
('Jablko a hruška a meruňka', '', '')
('Jablko a hruška', ' a ', 'meruňka')
('', '', 'Jablko a hruška a meruňka')

Tip: Pro každou metodu typu str si můžete zobrazit oficiální nápovědu – v ní ale ignorujte parametr self (tím se budeme zabývat podrobně na konci semestru). Po napsání části str. můžete stisknout klávesu Tab a nechat si doplnit všechny existující metody.

In [19]:
help(str.split)
Help on method_descriptor:

split(self, /, sep=None, maxsplit=-1) unbound builtins.str method
    Return a list of the substrings in the string, using sep as the separator string.

      sep
        The separator used to split the string.

        When set to None (the default value), will split on any whitespace
        character (including \n \r \t \f and spaces) and will discard
        empty strings from the result.
      maxsplit
        Maximum number of splits.
        -1 (the default value) means no limit.

    Splitting starts at the front of the string and works to the end.

    Note, str.split() is mainly useful for data that has been intentionally
    delimited.  With natural text that includes punctuation, consider using
    the regular expression module.

Zjišťovací metody¶

Typ str nabízí mnoho metod bez parametrů, které vracejí hodnoty True/False podle toho, jestli daný string splňuje určité vlastnosti.

Metoda Krátký popis
islower Vrací True, je-li ve stringu alespoň jedno písmeno a všechna písmena jsou malá. Znaky, které nejsou písmeny, výsledek neovlivní.
isupper Vrací True, je-li ve stringu alespoň jedno písmeno a všechna písmena jsou velká. Znaky, které nejsou písmeny, výsledek neovlivní.
istitle Vrací True, je-li ve stringu alespoň jedno písmeno a mají-li ve stringu všechna slova první písmeno velké a ostatní malá. Znaky, které nejsou písmeny, výsledek neovlivní.
isalpha Vrací True, je-li string neprázdný a všechny jeho znaky jsou v sadě Unicode považovány za písmena.
isdecimal Vrací True, je-li string neprázdný a všechny jeho znaky mohou být použity pro zápis čísel o základu 10.
isdigit Vrací True, je-li string neprázdný a všechny jeho znaky jsou v sadě Unicode považovány za číslice. Vedle běžných číslic a číslic zapsaných jako indexy či exponenty sem patří i číslice dalších jazyků – např. arabsko-indické.
isnumeric Vrací True, je-li string neprázdný a všechny jeho znaky jsou v sadě Unicode považovány za reprezentanty čísel. Sem patří vedle číslic i řada dalších znaků reprezentujících některé zlomky, římské číslice a jiné symboly. Platí isdecimal() ⊆ isdigit() ⊆ isnumeric().
isalnum Vrací True, je-li string neprázdný a všechny znaky představují písmena, číslice či čísla. Za alfanumerický je znak c považován v případě, vrací-li True alespoň jedna z metod c.isalpha(), c.isdecimal(), c.isdigit(), c.isnumeric().
isspace Vrací True, je-li string neprázdný a všechny jeho znaky jsou v sadě Unicode klasifikovány jako bílé znaky.
isprintable Vrací True, je-li string prázdný, nebo obsahuje pouze tisknutelné znaky. Za netisknutelné znaky jsou mimo jiné považovány všechny bílé znaky s výjimkou obyčejné mezery (tedy naříklad pevná mezera '\xA0' je netisknutelný znak).
isascii Vrací True, je-li string prázdný, nebo mají všechny jeho znaky kód menší nebo roven 255 (0x7F).
isidentifier Vrací True, je-li string platným identifikátorem podle pravidel Pythonu.
In [4]:
# Write your exercise code here
print("abc def".islower())
print("A Q".isupper(),"\n")

print("abc def".isalpha(),"\n")

print("162".isdecimal())
print("16.2".isdecimal())
print("16.2".isnumeric(),"\n")

print("abc def".isprintable())
print("abc\tdef".isprintable())
True
True 

False 

True
False
False 

True
False

Vyhledávání podstringů¶

Pro vyhledávání podřetězců má typ str v Pythonu celou sadu metod. Všechny tyto metody mají tři parametry: Povinným argumentem je hledaný podstring, volitelnými parametry start a end lze omezit hledání na podřetězec v rozsahu slice [start:end]. Parametry start a end nelze předat pojmenovaným způsobem, proto potřebujete-li zadat parametr end, musíte zadat i start.

Metody Krátký popis
count Vrací počet nepřekrývajících se výskytů zadaného podstringu.
find, rfind Vracejí pozici počátku prvního výskytu zadaného podstringu. Není-li podstring nalezen, vrátí -1. Metoda rfind prohledává zprava.
index, rindex Pracují stejně jako metody find, resp. rfind. Liší se pouze tím, že nenajdou-li hledaný řetězec, vyvolají ValueError.
startswith, endswith Vracejí True v případě, začíná-li (resp. končí-li) prohledávaný řetězec zadaným podstringem. Prvním argumentem může být i n-tice stringů.

Příklady použití těchto metod zkuste vymyslet samostatně.

In [1]:
# Write your exercise code here
print("babab bab bababa".count("bab"))
print("babab bab bababa".count("bab", 0, 4))
print("babab bab bababa".startswith("bab"))
3
1
True

Metody nahrazování¶

Často potřebujeme nejen zkontrolovat, jestli string obsahuje zadaný podřetězec, ale také ho nahradit nějakým jiným stringem. V nejjednodušším případě k tomu stačí použit metodu replace:

  • replace(old, new, count=-1):
    • parametr old představuje string, který hledáme
    • parametr new představuje náhradu za hledaný string
    • parametr count určuje maximální počet nahrazení (hodnota -1 znamená bez limitu)
In [35]:
s1 = "Ve slově standart se na konci nepíše t, ale d!"
print(s1.replace("t", "d"))
print(s1.replace("t", "d", 2))
print(s1)
Ve slově sdandard se na konci nepíše d, ale d!
Ve slově sdandard se na konci nepíše t, ale d!
Ve slově standart se na konci nepíše t, ale d!

Zmiňme ještě jednu nahrazovací metodu expandtabs(tabsize=8), která vrací kopii stringu, v níž jsou tabulátory (znak \t) nahrazeny sadou mezer tak, aby to odpovídalo zadané velikosti kroku tabulátoru. Vyzkoušejte na příkladu:

In [11]:
print("01\t012\t0123\t01234".expandtabs())
print("01\t012\t0123\t01234".expandtabs(4))
01      012     0123    01234
01  012 0123    01234

Ořezávání stringů¶

Při práci se vstupem od uživatele je často potřeba vstup zkontrolovat a případně upravit. Jedním z častých problémů jsou nadbytečné mezery (nebo obecně bílé znaky) na začátku nebo na konci řetězce. Tyto přebytečné znaky mohou způsobovat chyby při ukládání dat, vyhledávání, řazení nebo při kontrole unikátnosti. K odstranění těchto znaků je možné použít jednu z následujících metod:

  • lstrip (str.lstrip(chars=None)) – odstraňuje zadané znaky ze začátku stringu (zleva)
  • rstrip (str.rstrip(chars=None)) – odstraňuje zadané znaky z konce stringu (zprava)
  • strip (str.strip(chars=None)) – odstraňuje zadané znaky ze začátku i z konce stringu

Pokud parametr chars není zadaný, metody odstraní všechny bílé znaky (např. mezera, tabulátor nebo \n).

In [12]:
s1 = "       Nechci bílé znaky před ani za textem!  \n  ".strip()
s2 = "       Nechci bílé znaky před textem!  \n  ".lstrip()
s3 = "       Nechci bílé znaky za textem!  \n  ".rstrip()
s4 = "*   Nechci * před ani za textem!****".strip("*")
s5 = "*--Nechci * ani - za textem!**---".rstrip("*-")
print(s1, s2, s3, s4, s5, sep="\n")
Nechci bílé znaky před ani za textem!
Nechci bílé znaky před textem!  
  
       Nechci bílé znaky za textem!
   Nechci * před ani za textem!
*--Nechci * ani - za textem!

Všimněte si, že metody lstrip a rstrip neodebírají prefix, resp. suffix ­– parametr chars má význam množiny znaků, nikoliv podposloupnosti. Pokud chcete odebrat předponu nebo koncovku, můžete využít metody removeprefix a removesuffix.

In [37]:
s5 = "*--Nechci * ani - za textem!**---".removesuffix("*---")
print(s5)
*--Nechci * ani - za textem!*

Metody pro jednoduché formátování¶

Pro základní změnu velikosti písmen Python nabízí několik jednoduchých metod bez parametrů. Znaky, které nejsou považovány za písmena, nejsou těmito metodami ovlivněny.

Metoda Krátký popis
lower Vrátí nový string, ve kterém jsou všechna písmena převedena na malá písmena.
upper Vrátí nový string, ve kterém jsou všechna písmena převedena na velká písmena.
capitalize Vrátí nový string s prvním písmenem velkým a ostatními písmeny malými.
title Vrátí nový string, kde je první písmeno každého slova velké a ostatní písmena malá. Slova jsou definována jako skupiny po sobě jdoucích písmen. Tato definice funguje ve většině případů, ale má své limity (např. apostrofy jsou považovány za oddělovače slov).
In [13]:
s1 = "Text z malých písmen, VELKÝCH PÍSMEN a čísla 42."
print(s1.lower(), s1.upper(), s1.capitalize(), s1.title(), sep="\n")
s2 = "they're bill's friends from the UK"
print(s2.title())
text z malých písmen, velkých písmen a čísla 42.
TEXT Z MALÝCH PÍSMEN, VELKÝCH PÍSMEN A ČÍSLA 42.
Text z malých písmen, velkých písmen a čísla 42.
Text Z Malých Písmen, Velkých Písmen A Čísla 42.
They'Re Bill'S Friends From The Uk

Pro zlepšení čitelnosti delších textů může být potřeba zarovnat text doleva, doprava, nebo na střed. K tomu slouží metody ljust, rjust a center. Povinným pozičním parametrem všech těchto metod je požadovaná délka výsledného stringu. Text bude podle typu zarovnání standardně doplněn mezerami na začátku, na konci nebo z obou stran, aby dosáhl požadované délky. Pomocí druhého nepovinného parametru můžeme určit, jaký znak se má použít k doplnění stringu místo mezery.

In [38]:
print("|", "vlevo".ljust(20), "|", "uprostřed".center(20), "|", "vpravo".rjust(20), "|")
print("|", "jiny text".ljust(20), "|", "gjf".center(20), "|", "jjf ggyug".rjust(20), "|")
print ("Ahoj!".center(40, '-'))
| vlevo                |      uprostřed       |               vpravo |
| jiny text            |         gjf          |            jjf ggyug |
-----------------Ahoj!------------------

Formátování řetězců¶

Doposud jsme v případech, kdy jsme chtěli vytvořit "hezký" výstup pro uživatele, museli použít funkci print a vhodně zvolit objekty k zobrazení. Například, pokud jsme chtěli vypsat číselné hodnoty společně s krátkým vysvětlením, museli jsme funkci print předat "mix" proměnných a stringů:

In [39]:
hodiny = 2
minuty = hodiny * 60
print("vysledek:", hodiny, "hod je", minuty, "min")
vysledek: 2 hod je 120 min

U delšího nebo složitějšího textu však tento přístup není praktický. Navíc někdy potřebujeme výstup uložit pro další zpracování, nejen zobrazit pomocí funkce print. Mohli bychom sice číselné hodnoty převést na string a potom stringy zřetězit, Python ale nabízí elegantnější způsob formátování.

Pro znázornění si představte textovou šablonu s prázdnými místy, která později vyplníme konkrétními hodnotami:

Mil[ý/á] _______,
Váš výsledek 1. testu ZPRO je __________ bodů.

S pozdravem
_________

Aby Python věděl, které hodnoty umístit do kterých vynechaných míst, je potřeba jednotlivá vynechaná místa v šabloně nějak jednoznačně označit. K tomu se používají složené závorky a identifikátory:

Mil{y_a} {osloveni},
Váš výsledek 1. testu ZPRO je {soucet} bodů.

S pozdravem,
{podpis}.

Takovou textovou šablonu můžeme použít jako tzv. formátovací řetězec neboli f-string (anglicky formatted string literal). Formátovací řetězec se vytváří podobně jako obyčejný řetězec s tím rozdílem, že před první uvozovkou nebo apostrofem musíme přidat předponu f nebo F.

Pro uvedený příklad můžeme vytvořit jednoduchý program:

In [9]:
x = 6 + 5
string = f"Vysledek prikladu je {x + 34}." 
print(string)
string = f"Hodnota výrazu je {x / 3 + 34}." 
print(string)
string = f"Hodnota výrazu je {x / 3 + 34:.2f}." 
print(string)
Vysledek prikladu je 45.
Hodnota výrazu je 37.666666666666664.
Hodnota výrazu je 37.67.
In [16]:
y_a = "á"
osloveni = "Žofie"
ukol1 = 25
ukol2 = 40
ukol3 = 20
soucet = ukol1 + ukol2 + ukol3
podpis = "Váš cvičící"

vystup = f"""
Mil{y_a} {osloveni},
Váš výsledek 1. testu ZPRO je {soucet} bodů.

S pozdravem,
{podpis}
"""
print(vystup)
Milá Žofie,
Váš výsledek 1. testu ZPRO je 85 bodů.

S pozdravem,
Váš cvičící

Uvnitř složených závorek lze namísto identifikátorů proměnných použít jakékoli výrazy, volání funkcí apod.

Shrňme tedy základy práce s f-stringy, včetně několika dalších možností:

  • Pro f-stringy platí stejná pravidla jako pro obyčejné textové řetězce. Mohou je ohraničovat jednoduché, dvojité uvozovky nebo jejich trojice. Liší se pouze tím, že před úvodním uvozováním píšeme předponu f nebo F.
  • F-stringy mohou obsahovat nahrazovací pole s výrazy, jejichž hodnota se má dosadit do výsledného stringu.
  • Výrazy v nahrazovacích polích jsou vyhodnocovány zleva doprava, což má vliv pouze tehdy, pokud některé z výrazu mají vedlejší efekty.
  • F-stringy můžeme vytvořit jako zřetězení (součet) několika stringů, ale každý spojovaný řetězec by měl být f-string (jinak se nahrazovací pole v součtu neuplatní a budou brána jako běžný text).
  • Při ladění programu může být užitečné, pokud výraz v nahrazovacím poli zakončíme znakem =, což způsobí, že do stringu se vloží samotný zápis výrazu (včetně případných mezer a závěrečného rovnítka) a teprve za něj jeho výsledná hodnota.
In [47]:
from math import pi
r = 4
print(f"Obvod kruhu o poloměru {r =} je {2 * pi * r }")
Obvod kruhu o poloměru r =4 je 25.132741228718345
In [59]:
string = r"ahoj\"t\\ahoj"
print(string)
ahoj\"t\\ahoj

Poznámka: Předponu f/F lze kombinovat s předponou r/R, která označuje surový literál (anglicky raw literal). V surovém literálu nejsou podporovány escape sekvence, každý znak je interpretován doslovně. Výjimkou jsou pouze uvozovky, které musíme nadále zadávat se zpětným lomítkem. Surový řetězcový literál se hodí při práci s cestami k souborům nebo při zadávání regulárních výrazů.

Někdy se může stát, že jednu textovou šablonu chceme použít několikrát. V takovém případě nám f-string již nepomůže, protože v něm se "prázdná místa" doplňují automaticky a hned. Místo toho můžeme použít metodu format pro obyčejný string.

Poznámka: Historicky jsou f-stringy novější vlastností Pythonu, která byla zavedena až ve verzi 3.6. Naopak metoda format se objevila dříve již ve verzi Python 3. Pravidla pro formátování nahrazovacích polí pro f-stringy jsou fakticky převzatá z metody format.

Hlavička metody format má tvar format(*args, **kwargs), což znamená, že hodnoty dosazované do stringu můžeme specifikovat buď pomocí jejich pořadí, nebo jejich názvem. Názvy vkládaných hodnot nemusí být platné identifikátory, což činí metodu format obecnější než f-stringy.

In [60]:
s1 = "{} krát {} je {}.".format(2, 3, 2 * 3)
print(s1)
s2 = "Ahoj, jsem {jmeno}. A moje oblibené číslo je {cislo}."
print(s2.format(cislo=7, jmeno="Matěj"))
print(s2.format(cislo=42, jmeno="divný člověk"))
#print(s2.format("Žofie", 3))    # KeyError: není možné dosadit nepojmenovaný argument do pojmenovaného místa
2 krát 3 je 6.
Ahoj, jsem Matěj. A moje oblibené číslo je 7.
Ahoj, jsem divný člověk. A moje oblibené číslo je 42.

Příklady¶

  1. Silné heslo. Heslo budeme označovat jako silné, jsou-li splněná následující kritéria:
    1. Heslo obsahuje malá písmena latinské abecedy.
    2. Heslo obsahuje velká písmena latinské abecedy.
    3. Heslo obsahuje číslice.
    4. Heslo obsahuje alespoň jeden ze znaků ! " # $ % & ' ( ) * +.
    5. Délka hesla není menší než 8 znaků.

Napište funkci, která zjistí (a ve vhodné formě vrátí), které z těchto pěti kritérií silného hesla jsou pro použité heslo splněny.

In [72]:
def strong_password(passwd):
    a = b = c = d = e = False
    for znak in passwd:
        if znak.islower():
            a = True
        elif znak.isupper():
            b = True
        elif znak.isdecimal():
            c = True
        elif znak in "!\"#$%&'()*+":
            d = True
    if len(passwd) >= 8:
        e = True
    
    return (a, b, c, d, e, a & b & c & d & e)

print(strong_password("Moje8Heslo "))  # splňuje všechna kriteria
(True, True, True, False, True, False)
In [73]:
def strong_password(passwd):
    vysledek = {"a": False, "b": False, "c": False, "d": False, "e": False  }
    for znak in passwd:
        if znak.islower():
            vysledek["a"] = True
        elif znak.isupper():
            vysledek["b"] = True
        elif znak.isdecimal():
            vysledek["c"] = True
        elif znak in "!\"#$%&'()*+":
            vysledek["d"] = True
    if len(passwd) >= 8:
        vysledek["e"] = True
    return vysledek

print(strong_password("Moje8Heslo'"))  # splňuje všechna kriteria
{'a': True, 'b': True, 'c': True, 'd': True, 'e': True}
  1. Anagramy. Slovo je anagramem jiného slova, když ho lze získat přeuspořádáním jeho písmen. Napište funkci anagrams(word1, word2), která vrátí True, pokud jsou tato dvě slova anagramy, a False, pokud nejsou.
In [1]:
string = "abcdabcdda"
print(string.count("a"))
l = sorted(string)
print(l)
3
['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd', 'd']
In [79]:
def anagrams(str1, str2):
    return sorted(str1) == sorted(str2)

def anagrams(str1, str2):
    for x in set(str1+str2):
        if str1.count(x) != str2.count(x):
            return False
    return True
    

assert anagrams("reklama", "makrela")
assert anagrams("reklama", "marekll") == False
  1. Iniciály. Napište program, který se zeptá uživatele na jméno, pak na příjmení a potom vypíše iniciály – první písmena zadaných jmen. Iniciály jsou vždy velkými písmeny (i kdyby byl uživatel líný mačkat Shift). Možné náhodné mezery na začátku jména nebo příjmení také odstraňte. Pro převod zadaných jmén na iniciály použijte pomocnou funkci get_initials(name, surname).
In [82]:
def get_initials(name, surname):
    name = name.lstrip()
    surname = surname.lstrip()
    
    initials = name[0] + surname[0]
    
    return initials.upper()

get_initials("  jan ", "  novák")
Out[82]:
'JN'
  1. Frekvenční analýza. Napište funkci freq_analysis(text), která spočítá výskyt jednotlivých písmen (znaků) ve vstupním textu a vrátí výsledek jako slovník nebo jako seznam dvojic (znak, počet výskytů). Vypište znaky s počty jejich výskytů setříděné sestupně podle počtu výskytů.
In [2]:
def freq_analysis(text):
    dictionary = {}
    text = text.lower()
    for c in set(text):
        if c.isalnum():
            dictionary[c]=text.count(c)
    return dictionary

d = freq_analysis("All the world is a stage and all the men and women merely players.")
...
Out[2]:
Ellipsis
In [ ]:
def freq_analysis(text):
    dictionary = {}
    text = text.lower()
    for c in text:
        if c.isalnum():
            if c in dict:
                dictionary[c] += 1
            else:
                dictionary[c] = 1
    return dict

d = freq_analysis("All the world is a stage and all the men and women merely players.")
...
  1. Délka slov. Naprogramujte funkci, která zjistí délku každého slova v textu. Předpokládejme, že slova jsou oddělená pomocí obyčejných mezer (možná několika za sebou).
In [ ]:
def word_lengths(text):
    words = text.split()
    word_lengths = []
    for word in words:
        word_lengths.append(len(word))

    return word_lengths

assert word_lengths("   Toto   je    příklad textu s různě dlouhými slovy.  ") == [4, 2, 7, 5, 1, 5, 8, 6]
  1. Frekvenční analýza slov. Napište funkci freq_analysis(text), která spočítá výskytů jednotlivých slov ve vstupním textu a vrátí výsledek jako slovník nebo jako seznam dvojic (slovo, počet výskytů). Vypište slova s počty jejich výskytů setříděné vzestupně podle abecedy.
In [ ]:
def freq_analysis(text):
    ...

d = freq_analysis("This is a test. This is only a test, not a real situation.")
...
  1. Caesarova šifra. Vytvořte si funkci, která zrealizuje šifrování algoritmem Caesarové šifry. To šifrování spočívá v posouvání každého písmena řetězce o určitý počet znaků dle abecedy. Například slovo "Ahoj" se s posunem 1 převede na "Bipk". Ten posun – klič šifry – povolte vybrat uživateli. Jak by se naprogramovala funkce pro dešifrování?
In [ ]:
def caesar(text, shift):
   ...

a = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ"
assert caesar(a,12) == "mnopqrstuvwxyzabcdefghijkl MNOPQRSTUVWXYZABCDEFGHIJKL"

b = "All the world is a stage; And all the men and women merely players."
assert caesar(b, -2) == "Yjj rfc umpjb gq y qryec; Ylb yjj rfc kcl ylb umkcl kcpcjw njywcpq."
assert caesar(b, 26) == b
assert caesar(caesar(b,15), -15) == b
  1. Kryptoanalýza Caesarovy šifry. Caesarovu šifru lze velmi lehko vyluštit (tj. zjistit neznámý posun – tajný klíč). Zkuste naprogramovat dvě funkce, první implementuje tzv. metodu hrubé sily, druhá způsob frekvenční analýzy.
In [ ]:
print(caesar("Ask me, how to "))

def try_caesar(text):
    ...

try_caesar("Clguba vf n irel hfrshy cebtenzzvat ynathntr. Naq ubj fvzcyr vg vf... V ybir vg!") 
In [ ]:
def caesar_frequency_analysis(text):
    ...

caesar_frequency_analysis("Clguba vf n irel hfrshy cebtenzzvat ynathntr. Naq ubj fvzcyr vg vf... V ybir vg!")