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

Textový řetězec (string) je základní datový typ v Pythonu, používaný k uchování libovolných znaků, a to zpravidla textové informací. Stringy jsou neměnné (immutable) a hashovatelné, což znamená, že po provedení "modifikovatelné" operaci se vždy vytvoří nový string, původní se nemění. Stringy jsou instancemi třídy str.

Stringy můžeme vytvořit pomocí jednoduchých (apostrofy), dvojitých uvozovek nebo jejich trojic. První dva způsoby jsou téměř ekvivalentní. Rozdíl se může objevit v případě použití uvozovek uvnitř textu.

In [2]:
s1 = "Potřebuji \n\"'apostrofy'"
s2 = 'Potřebuji "uvozovky"'
print(s1)
print(s2)
Potřebuji 
"'apostrofy'
Potřebuji "uvozovky"

Poslední způsob se používá pro vytváření víceřádkových řetězců.

In [2]:
s3 = '''Jsem víceřádkový string,
vytvořený pomocí
trojic jednoduchých uvozovek.'''
print(s3)
Jsem víceřádkový string,
vytvořený pomocí
trojic jednoduchých uvozovek.

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

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("False"))
print(str("Python"))
print(repr("Python"))

# na seznam a zpět
x = "abc"
l = list(x)
print(l)
s = str(l)
print(s)
s = "".join(l)
print(s)

# operátory + a *
a = "abc" + " " + "eg" * 3
print(a)
1234
-3.5
(1+2j)
True
Python
'Python'
['a', 'b', 'c']
['a', 'b', 'c']
abc
abc egegeg

Pro stringy je možné používat základní operace jako testování, iterování, zřetězení, porovnání. Jsou k dispozici i indexování a vykrajování (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 tzn. být jiné než v tradičním lexikografickém uspořádání.

In [3]:
# opakovani:
s = "abcdef ahoj!"

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


print(s[0])
#s[-1] = "2" # chyba!
s= "2" + s[1:]
print(s)

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

c = "a"
if c in s:
    print("ano, je tam")  

print(s[2:4])
a b c d e f   a h o j ! 
a
2bcdef ahoj!
2 b c d e f   a h o j ! 
ano, je tam
cd

Pro zpracování jednotlivých znaků se mohou používat 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 [3]:
print(chr(0x20ac))    # Znak euro
print(chr(0x1D120))   # Houslový klíč
print(ord("€"))

x = "A"
y = ord(x)
print(x, y, chr(y))

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

print(sorted(["Ábc","Abc", "abc", "ABC"]))  # setřídí stringy podle kódů (vzestupně)
print(sorted(["Ábc","Abc", "abc", "ABC"], reverse=True)) # setřídí stringy podle kódů (sestupně)

# vytvoří setříděný seznam znaků
print(sorted("abhjsdvkdgcvsdgcdsjkzdg"))
€
𝄠
8364
A 65 A
False
97 65
['ABC', 'Abc', 'abc', 'Ábc']
['Ábc', 'abc', 'Abc', 'ABC']

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

Metody třídy str¶

Typ str v Pythonu je třída, a proto se během rozhovoru o textových řetězcích potřebujeme stručně seznámit s termínem metoda (anglicky method) z objektově orientovaného programování. Stringové metody jsou asi nejzajímavější částí, kterou budeme běžně používat v práci s textem.

Metody jsou sice stále funkce, ale protože jsou části třidy, interpret zachází s nimi maličko jinak. Při volání metody budeme používat tečkovou notaci textový_řetězec.název_metody(). Pak interpret předá té metodě odkaz na textový_řetězec jako počáteční argument. Další argumenty budeme předávat jako obvykle uvnitř závorek. Tyto argumenty mohou být nějaké jiné textové řetězce nebo něco jiného.

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

  • 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í. Ostatní detaily o metodách třídy str jsou k dispozici v dokumentaci https://docs.python.org/3/library/stdtypes.html#string-methods.

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

Spojování dvou stringů můžeme udělat pomocí operátoru +. Pokud chceme zřetězit více stringů, anebo dělat zřetězení v cyklu, výpočet se může kvůli neustálému vytváření nových instancí a kopírování předešlých výrazně zpomalit. V takovém případě je možné použít metodu join(iterable). Tato metoda očekává v argumentu iterable zdroj stringů, které sloučí, přičemž mezi ně vloží vždy obsah objektu, který ji volá. Pak ten zřetězený string vrátí jako svoji návratovou hodnotu.

In [19]:
ovoce = ["Jablko", "Hruška", "Meruňka"]
s1 = ", ".join(ovoce)       # Jako oddělovač používáme čárku s mezerou
s2 = "".join(ovoce)         # Prázdný řetězec znamená, že bude to zřetězování bez oddělovače
s3 = "; ".join("Jablko")    # Tady máme jako argument jen jeden string, Python ho považuje za tzv. generátor jednoznakových stringů
print(s1)
print(s2)
print(s3)
Jablko, Hruška, Meruňka
JablkoHruškaMeruňka
J; a; b; l; k; o

Stejně jako umíme stringy spojovat, občas je potřeba celý string rozložit na jednotlivé části. Tuto funkcionalitu nabízejí metody split(), rsplit(), partition(), rpartition(), splitlines().

Metoda split(sep=None, maxsplit=-1) má dva parametry, oba mají výchozí hodnotu. sep slouží k určeni podřetězce, který bude vystupovat jako oddělovač neboli separátor. Když nezadáme při volání první argument nebo bude None, jako separátor vystupují jeden či více sousedících bílých znaků. Jinak narazíme-li na dva sousední oddělovače, nesloučíme je v jeden, ale dostaneme na příslušném místě prázdný řetězec. Hodnota maxsplit určuje, maximálně kolikrát se daný separátor při rozdělování použije. Je-li v stringu nalezen vícekrát, další výskyty se ignorují. Výsledkem volání metody split() je seznam stringů, přičemž každý je částí původního stringu v odpovídajícím pořadí. Metoda rsplit() má stejné parametry a nabízí stejnou funkcionalitu, jen prohledává řetězec od konce.

In [25]:
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', 'a', 'hruška', 'a', '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']

Metody partition() a rpartition() se používají k podobnému učelu. Na rozdíl od metod split() a rsplit(), nevracejí seznam oddělených částí, ale n-tici (začátek, separátor, konec). Mají v závorce jen jeden parametr sep, a ten výchozí hodnotu nemá.

In [26]:
ntice1 = "Jablko a hruška a meruňka".partition(" a ")
ntice2 = "ZPRO_Cv13.ipynb".partition(".")
ntice3 = "Jablko a hruška a meruňka".partition(",")      # Separátor není nalezen
ntice4 = "Jablko a hruška a meruňka".rpartition(" a ")   # Hledáme separátor zprava
print(ntice1, ntice2, ntice3, ntice4, sep="\n")
ntice5 = "Jablko a hruška a meruňka".partition()         # TypeError: použití bez určení separátoru není povoleno
('Jablko', ' a ', 'hruška a meruňka')
('ZPRO_Cv13', '.', 'ipynb')
('Jablko a hruška a meruňka', '', '')
('Jablko a hruška', ' a ', 'meruňka')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[26], line 6
      4 ntice4 = "Jablko a hruška a meruňka".rpartition(" a ")   # Hledáme separátor zprava
      5 print(ntice1, ntice2, ntice3, ntice4, sep="\n")
----> 6 ntice5 = "Jablko a hruška a meruňka".partition()         # TypeError: použití bez určení separátoru není povoleno

TypeError: str.partition() takes exactly one argument (0 given)

Když chceme víceřádkový text rozdělit na jednotlivé řádky, je vhodné použití metody splitlines(keepends=False), která vrácí seznam stringů jednotlivých řádků. Standardně stringy ve vraceném seznamu nebudou obsahovat znaky ukončení řádku. Můžeme ale o tom požádat s hodnotou nepovinného pojmenovaného parametru jako True.

Pro chytřejší rozdělování stringů se budou používat regulární výrazy.

Ořezávání stringů¶

Často potřebujeme vstup od uživatele zkontrolovat, případně hned opravit. Jednou z běžných nepřesností na webu a v textech jsou zbytečné mezery na začátku či konci řetězce. Toto může vyprovokovat např. chyby v uložení dat, jejich vyhledávání a uspořádání. "Vyčistit" takové chyby v Pythonu nám pomůžou metody lstrip(), rstrip() a strip(), které odstraňují bílé znaky resp. ze začátku, z konce nebo ze začátku i konce stringu. Všechny bílé znaky uprostřed textu zůstanou.

Všechny tři uvedené metody jsou ale univerzálnější. Zavoláme-li je se zadaným argumentem, očekávají v něm string s množinou znaků, které mají na počátku a/nebo na konci stringu odebrat. Případné výskyty těchto znaků uvnitř textu samozřejmě zůstanou.

In [28]:
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 Pythonu také jsou metody removeprefix() a removesuffix(), které umějí odstranit zadanou předponu resp. příponu v našem stringu. Podrobnosti o nich snadno najděte v dokumentaci.

Vyhledávání podstringů¶

Teď se budeme zabývat vyhledáváním zadaného podstringů. Tomu účelu v Pythonu slouží celá sada metod. Všechny tyto metody kromě vlastně hledaného podstringu mají implicitní parametry start a end definující podstring nebo slice [stard:end] (to znamená od pozice start do pozice end a tu už ne) původního stringu, v němž se vykonává vyhledávání. Parametry start a end jsou poziční nikoliv pojmenované, proto potřebujete-li zadat konec prohledávaného slicu, musíte zadat i počáteční.

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í výjimku ValueError.
startswith(), endswith() Vracejí True v případě, začíná-li (resp. končí-li) prohledávaný řetězec zadaným stringem. Prvním argumentem může vystupovat i n-tice stringů.

Příklady použití těchto metod budou dost jednoduché, můžete je zkusit vymyslet samostatně.

In [4]:
# Write your exercise code here
print("a mamama mama".count("mam"))
print("a mamama mama".find("mam"))
print("a mamama mama".rfind("mam"))
print("a mamama mama".find("ham"))
print("a mamama mama".rfind("ham"))
print("a mamama mama".startswith("a "))
2
2
9
-1
-1
True

Metody nahrazování¶

Relativně často potřebujeme nejen zkontrolovat, obsahuje-li řetězec zadaný podstring, ale i nahradit ho nějakým jiným textem. V nejjednodušším případě stačí k tomu použit metodu replace(old:str, new:str, count:int=0). Jako první parametr metoda očekává hledaný nahrazovaný text, jako druhý text, který jej má nahradit, a ve třetím nepovinném maximálně povolený počet nahrazení. Nezadáme-li třetí parametr, nahradí se všechny výskyty.

In [9]:
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)

s = "a mamama mama"
print(s.replace("a","A"))
print(s.replace("am","*"))
print(s.replace("a",""))
print(s.replace("a","A",3))
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!
A mAmAmA mAmA
a m**a m*a
 mmm mm
A mAmAma mama

Zmiňme ještě jednu nahrazovací metodu expandtabs(tabsize=8), která vrací kopii osloveného stringu, v níž jsou tabulátory nahrazeny sadou mezer tak, aby to odpovídalo zadané velikosti kroku tabulátoru. Krok tabulátoru můžeme ukázat jako argument, defaultní hodnotou je 8 znaků.

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

Pro zajímavější případy nahrazování často je vhodné využít možností regulárních výrazů.

Zjišťovací metody¶

Třída str nabízí množinu bezparametrických metod vracejících hodnotu logického typu, která nás informuje o některých celkových vlastnostech textového řetězce. Příklady použití těchto metod zůstanou k samostatnému procvičení.

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.
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é.
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é.
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.
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 (pevná mezera '\xA0' je proto 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 [22]:
# Write your exercise code here
print("ahoj".islower())             # True
print("ahoj lidi_;\t\"".islower())  # True
print("ahojA".islower(), "\n")      # False

print("AHOJ!!! ".isupper())      # True
print("ahOj".isalpha())          # True
print("ahoOj ".isalpha(), "\n")  # False

print("23".isnumeric())           # True
print("2.3".isnumeric())          # False
print("2_3".isnumeric())          # False
print("-23".isnumeric())          # False
True
True
False 

True
True
False 

True
False
False
False

Metody pro jednoduché formátování¶

Pro jednoduché formátování, které se tyká změny velikosti písmen, Python nabízí několik snadných bezparametrických metod. Znaky, které se nepovažují za písmena, použití těchto metod neovlivní.

Metoda Krátký popis
lower() Vrátí nový string vzniklý převodem svého stringu na malá písmena.
upper() Vrátí nový string vzniklý převodem svého stringu na velká písmena.
capitalize() Vrátí nový string vzniklý převodem svého stringu na malá písmena s výjimkou prvního znaku, který bude velký.
title() Vrátí nový string vzniklý převodem svého stringu na malá písmena s prvními znaky všech slov velkými písmeny. Používá se jednoduchá jazykonezávislá definice slova jako skupiny po sobě jdoucích písmen. Tato definice funguje v mnoha kontextech, ale znamená to, že např. apostrofy mohou mít nepožadovaný vliv na výsledek.
In [47]:
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

Aby velké texty vypadaly čitelněji, může se objevit potřeba udělat zarovnávání doleva, doprava, nebo na střed. Pomohou v tom metody ljust(), rjust() a center() resp. Povinným pozičním parametrem všech těchto metod je požadovaná délka výstupního stringu. Zadaný text bude podle typu zarovnání standardně doplněn mezerami na konci a/nebo na začátku na požadovanou délku. V druhém nepovinném parametru můžeme určit, jaký znak se má použít k doplnění stringu místo standardní mezery.

In [48]:
print("|", "vlevo".ljust(20), "|", "uprostřed".center(20), "|", "vpravo".rjust(20), "|")
print ("Ahoj!".center(40, '.'))
| vlevo                |      uprostřed       |               vpravo |
.................Ahoj!..................

Formátovací řetězce a metoda format()¶

Zatím v případě, když jsme chtěli udělat nějaký pochopitelný výstup pro uživatele (např. nejen vypsat nějaké číslo ale doplnit výsledek krátkým vysvětlením), byli jsme nuceni používat ve funkci print() "mix" hodnot a výrazů.

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

Pro velké výstupy již to nebude tak snadno. A kromě toho někdy potřebujeme ten celý výstupní string uložit. Zřejmě můžeme vytvořit řetězec pomocí zřetězování. Python ale nabízí elegantnější způsob takového formátování.

Znázorníme to jako textovou šablonu s nějakými prázdnými místy, které potom chceme vyplnit konkrétními hodnotami.

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

S pozdravem
_________

Aby Python věděl, do kterého vynechaného místa co doplnit, je potřeba jednotlivá vynechaná místa ve formuláři 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 nebo f-string (anglicky formatted string literal). Formátovací řetězec se vytvořuje stejně jako obyčejný řetězec, jen aby bylo jasné, že nejde o "standardní" string ale f-string, před první uvozovky musíme přidat předponu f nebo F.

Pák pro uvedenou situaci můžeme vytvořit jednoduchý programní "skript":

In [54]:
y_a = "á"
osloveni = "Žofie"
ukol1 = 25
ukol2 = 40
ukol3 = 20
soucet = ukol1 + ukol2 + ukol3
podpis = "Já"

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

S pozdravem,
{podpis}
"""
print(vystup)

x = fr"\"ahoj"
print(x)
Milá Žofie,
Váš výsledek 1. testu ZPRO je 85 bodů.

S pozdravem,
Já

\"ahoj

Místo identifikátorů proměnných v složených závorkách vždy je možné použít jakékoli výrazy, volání funkcí apod.

V literatuře se práce s f-stringy často označuje jako literálová stringová interpolace (anglicky Literal String Interpolation). To znamená, že f-stringový literál nedefinuje ten textový řetězec přesně, ale obsahuje různé interpolace, jejichž vyhodnocením získáme konečný tvar.

Shrneme tedy základy pro práci s f-stringy, které nám ukážou i některé další možnosti:

  • 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 ohraničením píšeme předponu f nebo F.
  • F-stringy mohou obsahovat nahrazovací pole, v nichž se mohou vyskytovat výrazy, jejichž hodnota se má zobrazit.
  • Výrazy v nahrazovacích polích jsou vyhodnocovány zleva doprava, což má vliv na výsledek pouze tehdy, budou-li mít některé vyhodnocované výrazy vedlejší efekt.
  • F-stringy můžeme vytvořit jako součet nebo složeni několika stringů, avšak musíme dát pozor, aby všechny sčítance obsahující nahrazovací pole byly zadány jako f-stringy, protože jinak se v součtu uplatní pouze jako obyčejný string.
  • Při ladění můžeme využít toho, že bude-li výraz v složených uvozovkách končit rovnítkem, bude vypsán celý ten výraz včetně případných mezer a závěrečného rovnítka, a za něj pak výsledek interpolace.
  • Předponu f/F lze doplnit i předponou r/R, která určuje tzv. surový literál.

Poznámka: Surový (ve smyslu nezpracovaný) literál (anglicky raw literal) nerespektuje escape sekvence, každý znak v něm představuje sám sebe. Výjimkou jsou pouze uvozovky, je musíme nadále zadávat se zpětným lomítkem. Surový stringový literál se výhodně používá při zadávání cest k souborům nebo regulárních výrazů.

In [64]:
print(f"abcd \\\tvgh")
print(fr"abcd \\\tvgh")
abcd \	vgh
abcd \\\tvgh

Někdy se může stát, že jednu textovou šablonu chceme použít několikrát. V tom nám f-string již tak snadno nepomůže, protože se do něj "prázdná místa" doplňují automaticky a hned. V takovém případě je možné použit metodu format() pro obyčejný string.

Poznámka: Pravda je v tom, že f-stringy je novější možnost Pythonu, která byla zavedena až ve verzi 3.6. Metoda format() se objevila dřív spolu s Python 3. Pravidla pro formátování nahrazovacích polí v f-strinzích jsou fakticky převzatá z metody format().

Hlavička metody format() má tvar format(*args, **kwds), což znamená, že její argumenty můžeme odvolávat jak jejich pořadím, tak i jejich názvem. To dává výhodu oproti formátovacím řetězcům. Nejsme povinní dosazované hodnoty vždy jmenovat: nepojmenované argumenty se dosadí postupně do nepojmenovaných míst v textové šabloně.

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

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 [24]:
def strong_password(passwd):
    a = b = c = d = e = False
    for x in passwd:
        if x.islower():
            a = True
        if x.isupper():
            b = True
        if x.isnumeric():
            c = True
        if x in "!\"#$%&'()*+":
            d = True
    if len(passwd)>=8:
        e = True
    return a, b, c, d, e

print(strong_password("Moje8Heslo'"))  # splňuje všechna kriteria
(True, True, True, True, 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 [25]:
str = "abcdabcdda"
l = sorted(str)
print(l)
['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd', 'd']
In [41]:
def anagrams(str1, str2):
    return sorted(str1) == sorted(str2)

assert anagrams("reklama", "makrela")
assert anagrams("reklama", "marekll") == False
assert anagrams("reklama", "mareklla") == False
assert anagrams("reklama", "marek") == False
assert anagrams("reklama", "mareklaa") == False
In [37]:
def anagrams(str1, str2):
       
    for x in set(str1): # for x in str1:  
        if str1.count(x) != str2.count(x):
            return False
    return True       

assert anagrams("reklama", "makrela")
assert anagrams("reklama", "marekll") == False
assert anagrams("reklama", "mareklla") == False
assert anagrams("reklama", "marek") == False
assert anagrams("reklama", "mareklaa") == False
In [40]:
def anagrams(str1, str2):
       
    for x in str1:  
        if x not in str2:
            return False
        else:
            str2 = str2.replace(x,"",1)
    return len(str2)==0       

assert anagrams("reklama", "makrela")
assert anagrams("reklama", "marekll") == False
assert anagrams("reklama", "mareklla") == False
assert anagrams("reklama", "marek") == False
assert anagrams("reklama", "mareklaa") == 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 [15]:
def get_initials(name, surname):

    name = name.lstrip()
    surname = surname.lstrip()
 
    # Získáme první písmeno ze jména
    initials = name[0] + surname[0]

    # Převedeme iniciály na velká písmena
    return initials.upper()

assert get_initials("  jan ", "  novák") == "JN"

x  = input("Zadej jméno:")
y  = input("Zadej příjmení:")
v = get_initials(x,y)
print(f"tvé iniciály jsou {v}.")
tvé iniciály jsou AF.
  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 [17]:
def freq_analysis(text):
    dict = {}
    text = text.lower()
    for c in set(text):
        if c.isalnum():
            dict[c]=text.count(c)
    return dict

d = freq_analysis("All the world is a stage and all the men and women merely players.")
print(d)

#v = sorted(d.items(), key=lambda x: x[1], reverse=True)
{'l': 7, 'r': 3, 'm': 3, 't': 3, 'a': 7, 'e': 8, 'g': 1, 'n': 4, 'p': 1, 'd': 3, 'h': 2, 's': 3, 'y': 2, 'i': 1, 'w': 2, 'o': 2}
In [18]:
def freq_analysis(text):
    dict = {}
    text = text.lower()
    for c in text:
        if c.isalnum():
            if c in dict:
                dict[c]+=1
            else:
                dict[c] = 1
    return dict

d = freq_analysis("All the world is a stage and all the men and women merely players.")
print(d)


#v = sorted(d.items(), key=lambda x: x[1], reverse=True)
{'a': 7, 'l': 7, 't': 3, 'h': 2, 'e': 8, 'w': 2, 'o': 2, 'r': 3, 'd': 3, 'i': 1, 's': 3, 'g': 1, 'n': 4, 'm': 3, 'y': 2, 'p': 1}
  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 [23]:
def word_lengths(text):
    
    words = text.split()
    word_lengths = []
    for word in words:
        word = word.strip(".,!?()[]{}'\"")
        word_lengths.append(len(word))

    return word_lengths

text = "Toto je příklad textu s různě dlouhými slovy."
print(word_lengths(text))
assert word_lengths("   Toto   je    příklad textu s různě dlouhými slovy.  ") == [4, 2, 7, 5, 1, 5, 8, 5]
[4, 2, 7, 5, 1, 5, 8, 5]
  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 [26]:
def freq_analysis(text):
    text = text.lower()
    words = text.split()
    for i in range(len(words)):
        words[i] = words[i].strip(".,!?()[]{}'\"")

    d = {}
    for word in words:
        if word in d:
            d[word] += 1
        else:
            d[word] = 1

    return d

d = freq_analysis("This is a test. This is only a test, not a real situation.")
print(d)
d_sorted = dict(sorted(d.items()))
print(d_sorted)
{'this': 2, 'is': 2, 'a': 3, 'test': 2, 'only': 1, 'not': 1, 'real': 1, 'situation': 1}
{'a': 3, 'is': 2, 'not': 1, 'only': 1, 'real': 1, 'situation': 1, 'test': 2, 'this': 2}
  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 [2]:
def caesar_frequency_analysis(text):
    ...

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