Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions courses/pyladies/info.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ plan:
materials:
- lesson: beginners/def
- lesson: beginners/str
- lesson: beginners/str-index-slice
- lesson: beginners/str-methods
- lesson: beginners/fstring
- title: Řetězcový tahák
url: https://pyvec.github.io/cheatsheets/strings/strings-cs.pdf
Expand Down
188 changes: 188 additions & 0 deletions lessons/beginners/str-index-slice/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# Výběr z řetězců


Už umíš spojovat dohromady kratší řetězce:

```python
spojeny_retezec = 'a' + 'b'
dlouhy_retezec = 'ó' * 100
```
Teď se podíváme na opačný proces: jak z dlouhého
řetězce dostat kratší součásti.
Začneme jednotlivými znaky.


## Výběr znaku

Konkrétní znak na dané pozici se z řetězce dá vybrat operací *vybrání prvku*
(angl. *subscripting*),
která se píše podobně jako volání funkce, jen s hranatými závorkami.
Třeba takhle se dá vybrat znak na páté pozici:

```python
pate_pismeno = 'čokoláda'[5]

print(pate_pismeno)
```

Funguje to? Dostal{{a}} jsi opravdu páté písmeno?

{% filter solution %}
Nedostal{{a}} – dostal{{a}} jsi *šesté* písmeno.
{% endfilter %}

Jak sis možná už všiml{{a}}, programátoři počítají od nuly.
„První“ prvek má vždy číslo nula, druhý číslo jedna a tak dál.

Stejně je to i se znaky v řetězcích. První písmeno má číslo nula,
druhé jedna, ... a osmé písmeno má číslo sedm.

Proč je tomu tak?
K úplnému pochopení důvodů by ses potřeboval{{a}}
naučit něco o ukazatelích a polích,
což nebude hned, takže pro teď nám bude
stačit vědět,
že programátoři jsou prostě divní.

Nebo aspoň že mají rádi divná čísla – jako nulu.

```plain
[0] [1] [2] [3] [4] [5] [6] [7]

╭───┬───┬───┬───┬───┬───┬───┬───╮
│ Č │ o │ k │ o │ l │ á │ d │ a │
╰───┴───┴───┴───┴───┴───┴───┴───╯
```


A když už jsme u divných čísel,
co se asi stane, když budu vybírat písmena pomocí záporných čísel?

{% filter solution %}
```python
print('Čokoláda'[-1]) # → a
print('Čokoláda'[-2]) # → d
print('Čokoláda'[-3]) # → á
print('Čokoláda'[-4]) # → l
```

Záporná čísla vybírají písmenka od konce.

```plain
[0] [1] [2] [3] [4] [5] [6] [7]
[-8][-7][-6][-5][-4][-3][-2][-1]
╭───┬───┬───┬───┬───┬───┬───┬───╮
│ Č │ o │ k │ o │ l │ á │ d │ a │
╰───┴───┴───┴───┴───┴───┴───┴───╯
```
{% endfilter %}



## Sekání řetězců

Kromě jednotlivých znaků můžeme vybírat i delší části – odborně
*podřetězce* (angl. *substrings*).

Zkus, co dělá tenhle program:

```python
retezec = 'čokoláda'
kousek = retezec[5:]
print(kousek)
```

{% filter solution %}
Zápis `retezec[5:]` vybere *podřetězec* od znaku číslo 5 dál.
{% endfilter %}

Dá se použít i `retezec[:5]`,
který vybere všechno *až po* znak číslo 5.
Ne však znak 5 samotný, což je možná trochu zarážející,
ale je potřeba s tím počítat.
Poslední prvek není ve výběru obsažen, podobně jako `range(5)` neobsahuje
číslo 5.

Ačkoli je tohle chování divné, má hezké důsledky.
Všimni si třeba, že `retezec[:5] + retezec[5:]` ti dá zpět původní `retezec`.

Podobnému vybírání podřetězců se říká „sekání“ řetězců
(angl. *string slicing*).

Sekání „od“ a „do“ se dá kombinovat.
Zkus si to: co asi udělají následující příkazy?

```python
retezec = 'čokoláda'
print(retezec[:4])
print(retezec[2:6])
print(retezec[-3:])
print(retezec[:])
```

{% filter solution %}
Zápis `retezec[od:do]` vybere *podřetězec* od pozice `od` do pozice `do`.
Když jednu z hodnot vynecháš, vybírá se od začádku, resp. do konce.

```python
retezec = 'čokoláda'
print(retezec[:4]) # → čoko
print(retezec[2:6]) # → kolá
print(retezec[-3:]) # → áda
print(retezec[:]) # → čokoláda
```
{% endfilter %}

Určování vhodných čísel, *indexů*, občas vyžaduje trochu zamyšlení.

U sekání (s `:`) pomáhá očíslovat si „hranice“ mezi znaky,
abys v tom měl{{a}} lepší přehled:

{{ anchor('slicing-diagram') }}
```plain
╭───┬───┬───┬───┬───┬───┬───┬───╮
│ Č │ o │ k │ o │ l │ á │ d │ a │
├───┼───┼───┼───┼───┼───┼───┼───┤
│ │ │ │ │ │ │ │ │
0 1 2 3 4 5 6 7 8
-8 -7 -6 -5 -4 -3 -2 -1

╰───────────────╯
'čokoláda'[:4] == 'čoko'

╰───────────────╯
'čokoláda'[2:6] == 'kolá'

╰───────────╯
'čokoláda'[-3:] == 'áda'
```


## Cvičení

Zkus napsat funkci `zamen(retezec, pozice, znak)`.

Tato funkce vrátí řetězec, který má na dané pozici
daný znak; jinak je stejný jako původní `retezec`. Například:

```python
# Zaměň třetí znak ve slově "čokoláda"
print(zamen('čokoláda', 3, 'u')) # → čokuláda
```

Pozor na to, že řetězce v Pythonu nelze měnit.
Nemůžeš v existujícím řetězci zaměnit jeden znak za jiný;
musíš vytvořit nový řetězec poskládaný z částí toho starého.

{% filter solution %}
```python
def zamen(retezec, pozice, znak):
"""Zamění znak na dané pozici

Vrátí řetězec, který má na dané pozici daný znak;
jinak je stejný jako vstupní retezec
"""

return retezec[:pozice] + znak + retezec[pozice + 1:]
```
{% endfilter %}
5 changes: 5 additions & 0 deletions lessons/beginners/str-index-slice/info.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
title: Výběr z řetězců
style: md
attribution:
- Pro PyLadies Brno napsal Petr Viktorin, 2014-2019.
license: cc-by-sa-40
110 changes: 110 additions & 0 deletions lessons/beginners/str-methods/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Řetězcové funkce a metody

Řetězce umí všelijaké triky.
Funkcí `len()` můžeš zjistit, jak je řetězec dlouhý;
operátorem `in` pak jestli v sobě obsahuje daný podřetězec.

<table class="table">
<tr>
<th>Zápis</th>
<th>Popis</th>
<th>Příklad</th>
</tr>
<tr>
<td><code>len(r)</code></td>
<td>Délka řetězce</td>
<td><code>len('čokoláda')</code></td>
</tr>
<tr>
<td><code>x&nbsp;in&nbsp;r</code></td>
<td>True pokud je řetězec <code>x</code> obsažen v <code>r</code></td>
<td><code>'oko' in 'čokoláda'</code></td>
</tr>
<tr>
<td><code>x&nbsp;not&nbsp;in&nbsp;r</code></td>
<td>Opak <code>x in r</code></td>
<td><code>'dub' not in 'čokoláda</code></td>
</tr>
</table>

Řetězce vždy berou v potaz velikost písmen,
takže např. `'ČOKO' in 'čokoláda'` je `False`.
Kdybys chtěl{{a}} porovnávat bez ohledu na velikost písmen,
musel{{a}} bys oba řetězce převést třeba na malá písmena
a pak je porovnat.

A jak se převádí na malá písmena?
K tomu budeme potřebovat další novou vlastnost Pythonu: metody.

## Metody

*Metoda* (angl. *method*) je jako funkce – něco, co se dá zavolat.
Na rozdíl od funkce je svázaná s nějakým *objektem* (hodnotou).
Volá se tak, že se za objekt napíše tečka,
za ní jméno metody a za to celé se, jako u funkcí, připojí závorky
s případnými argumenty.

Řetězcové metody `upper()` a `lower()`
převádí text na velká, respektive malá písmena.
Zkus si to!

```python
retezec = 'Ahoj'
print(retezec.upper())
print(retezec.lower())
print(retezec)
```

> [note]
> Všimni si, že původní řetězec se nemění; metoda vrátí nový řetězec, ten
> starý zůstává.
>
> To je obecná vlastnost řetězců v Pythonu: jednou existující řetězec se už
> nedá změnit, dá se jen vytvořit nějaký odvozený.
> S touto vlastností už ses mohl{{a}} setkat při psaní funkce `zamen`.


### Iniciály

Pro procvičení metod a vybírání znaků si zkus napsat program,
který se zeptá na jméno, pak na příjmení
a pak vypíše iniciály – první písmena zadaných jmen.

Iniciály jsou vždycky velkými písmeny
(i kdyby byl uživatel líný mačkat Shift).

{% filter solution %}
```python
jmeno = input('Zadej jméno: ')
prijmeni = input('Zadej příjmení ')
inicialy = jmeno[0] + prijmeni[0]
print('Iniciály:', inicialy.upper())
```

Způsobů, jak takový program napsat, je více.
Lze například zavolat `upper()` dvakrát – zvlášť na jméno a zvlášť na příjmení.

Nebo to jde zapsat i takto –
metoda se dá volat na výsledku jakéhokoli výrazu:

```python
jmeno = input('Zadej jméno: ')
prijmeni = input('Zadej příjmení ')
print('Iniciály:', (jmeno[0] + prijmeni[0]).upper())
```

Doporučuji spíš první způsob, ten se smysluplnými názvy proměnných.
Je sice delší, ale mnohem přehlednější.
{% endfilter %}


### A další

Řetězcových metod je celá řada.
Nejužitečnější z nich najdeš v [taháku](https://pyvec.github.io/cheatsheets/strings/strings-cs.pdf), který si můžeš stáhnout či vytisknout.
Podívej se na ně a zjisti, co dělají.

A úplně všechny řetězcové metody jsou popsány v [dokumentaci Pythonu](https://docs.python.org/3/library/stdtypes.html#string-methods) (anglicky; plné věcí, které ještě neznáš).

Všimni si, že `len` není metoda, ale funkce; píše se `len(r)`, ne `r.len()`.
Proč tomu tak je, to za nějakou dobu poznáš.
5 changes: 5 additions & 0 deletions lessons/beginners/str-methods/info.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
title: Řetězcové funkce a metody
style: md
attribution:
- Pro PyLadies Brno napsal Petr Viktorin, 2014-2019.
license: cc-by-sa-40
Loading