This commit is contained in:
Priec
2026-02-28 23:21:09 +01:00
parent ce6b9b01d9
commit 5182e2f833
5 changed files with 945 additions and 86 deletions

View File

@@ -6,10 +6,26 @@ version = 4
name = "JR-priprava-na-skusku6" name = "JR-priprava-na-skusku6"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"itertools",
"serde", "serde",
"serde_json", "serde_json",
] ]
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "itertools"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
dependencies = [
"either",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.17" version = "1.0.17"

View File

@@ -4,5 +4,6 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
itertools = "0.14.0"
serde = { version = "1.0.228", features = ["derive"] } serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149" serde_json = "1.0.149"

View File

@@ -1,64 +1,22 @@
use JR_priprava_na_skusku6::priprava3; use std::collections::BTreeMap;
use itertools::Itertools;
use std::cmp::Reverse;
use std::collections::HashSet;
use std::collections::HashMap;
fn main() { fn main() {
priprava3::spusti(); // priprava3::spusti();
match std::fs::read_to_string("subor.txt") {
Ok(x) => print!("{x}"),
Err(y) => print!("{y}"),
};
}
fn nacitaj_a_parsuj(cesta: &str) -> Result<i32, Box<dyn std::error::Error>> { let input = vec![1, 3, 2, 1, 2, 3, 1, 1, 2];
let obsah = match std::fs::read_to_string(cesta) { let sorted = input.iter().sorted().collect::<Vec<_>>();
Ok(s) => s, let mut vys: HashMap<i32, usize> = HashMap::new();
Err(e) => return Err(Box::new(e)), for (i, j) in &sorted.into_iter().chunk_by(|&x| x) {
}; // vys.insert(i, j);
let cislo = match obsah.trim().parse::<i32>() { print!("{:#?}", i);
Ok(n) => n, let r = j.cloned().collect::<Vec<_>>();
Err(e) => return Err(Box::new(e)), vys.insert(*i, r.len());
}; print!("{:#?}", r);
Ok(cislo)
}
fn nacitaj_a_parsuj2(cesta: &str) -> Result<i32, Box<dyn std::error::Error>> {
let obsah = std::fs::read_to_string(cesta)?;
let cislo = obsah.trim().parse::<i32>()?;
Ok(cislo)
}
fn prvy_sused(vektor: &[i32], index: usize) -> Option<i32> {
if index == 0 {
return None;
}
let predchadzajuci = index.checked_sub(1);
match predchadzajuci {
Some(i) => {
if i < vektor.len() {
Some(vektor[i])
} else {
None
}
}
None => None,
} }
println!("{:#?}", vys)
} }
fn prvy_sused2(vektor: &[i32], index: usize) -> Option<i32> {
if index == 0 {
return None;
}
let predchadzajuci = index.checked_sub(1)?;
if predchadzajuci < vektor.len() {
return Some(vektor[predchadzajuci]);
}
None
}
fn nacitaj_json(cesta: &str) -> Option<Vec<String>> {
let nacitane = std::fs::read_to_string(cesta).ok()?;
let vec = serde_json::from_str::<Vec<String>>(nacitane.as_str());
Some(vec.ok()?)
}

View File

@@ -2,34 +2,74 @@ use std::fmt;
use std::collections::HashMap; use std::collections::HashMap;
pub fn spusti() { pub fn spusti() {
let mut mapa: HashMap<String, i32> = HashMap::new(); let z1 = Zamestnanec::new("Meno", "1 oddelenie", 1000);
// Vloženie let z2 = Zamestnanec::new("Meno2", "2 oddelenie", 1300);
mapa.insert("Anna".to_string(), 25); let z3 = Zamestnanec::new("Meno3", "2 oddelenie", 1100);
mapa.insert("Boris".to_string(), 30); let z: &[Zamestnanec] = &[z1, z2, z3];
// celkovy_plat_na_oddeleni(z);
// Čítanie — vráti Option<&V> // pocet_na_oddeleni(z);
let vek: Option<&i32> = mapa.get("Anna"); // Some(&25) // vypis_statistiky2(z);
let vek: Option<&i32> = mapa.get("Cyril"); // None oddelenie_s_najvyssim_platom(z);
// Kontrola existencie
let existuje: bool = mapa.contains_key("Anna"); // true
// Iterácia
for (meno, vek) in &mapa {
println!("{}: {}", meno, vek);
}
}
struct Kniha { nazov: String, rok: u16 }
impl fmt::Display for Kniha {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.nazov, self.rok)
}
} }
#[derive(Debug)] #[derive(Debug)]
struct Zamestnanec { plat: u32 } pub struct Zamestnanec { meno: String, oddelenie: String, plat: u32 }
struct Student { meno: String, vek: u8, priemer: f32 } impl Zamestnanec {
pub fn new(meno: &str, oddelenie: &str, plat: u32) -> Self {
Self {
meno: meno.to_string(),
oddelenie: oddelenie.to_string(),
plat
}
}
}
pub fn pocet_na_oddeleni(zamestnanci: &[Zamestnanec]) -> HashMap<String, usize> {
let mut mapa: HashMap<String, usize> = HashMap::new();
// mapa.entry(zamestnanci).and_modify(|counter| *counter += 1).or_insert(1);
// println!("{:#?}", zamestnanci);
for x in zamestnanci {
mapa.entry(x.oddelenie.clone()).and_modify(|counter| *counter += 1).or_insert(1);
}
// println!("{:#?}", mapa);
mapa
}
pub fn celkovy_plat_na_oddeleni(zamestnanci: &[Zamestnanec]) -> HashMap<String, u32> {
let mut mapa: HashMap<String, u32> = HashMap::new();
for x in zamestnanci {
mapa.entry(x.oddelenie.clone()).and_modify(|c| *c += x.plat).or_insert(x.plat);
}
// println!("{:#?}", mapa);
mapa
}
pub fn vypis_statistiky(zamestnanci: &[Zamestnanec]) {
let mut mapa: HashMap<String, (usize, u32)> = HashMap::new();
for x in zamestnanci {
mapa.entry(x.oddelenie.clone()).and_modify(|(count, total)| {
*count += 1;
*total += x.plat;
}).or_insert((1, x.plat));
}
}
pub fn vypis_statistiky2(zamestnanci: &[Zamestnanec]) {
let pocet = pocet_na_oddeleni(zamestnanci);
let plat = celkovy_plat_na_oddeleni(zamestnanci);
for oddelenie in pocet.keys() {
println!("Pocet ludi:{:#?}, a ich plat: {:#?}", *pocet.get(oddelenie).unwrap_or(&0), *plat.get(oddelenie).unwrap_or(&0));
}
println!("{:#?}, {:#?}", pocet, plat);
}
pub fn oddelenie_s_najvyssim_platom(zamestnanci: &[Zamestnanec]) -> Option<String> {
let plat = celkovy_plat_na_oddeleni(zamestnanci);
let max = plat.iter().max_by_key(|x| *x);
println!("{:#?}", max);
match max {
Some(x) => return Some(x.0.clone()),
None => None,
}
}

844
priprava/rust_priprava8.md Normal file
View File

@@ -0,0 +1,844 @@
# String, &str, char — krok za krokom
Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej.
---
## Kapitola 1: Čo je čo
V Ruste existujú 3 typy pre prácu s textom:
| Typ | Čo to je | Vlastní dáta? | Veľkosť |
|-----|----------|---------------|---------|
| `String` | Vlastnený, meniteľný reťazec na heape | Áno | Rastie/zmenšuje sa |
| `&str` | Referencia na kúsok textu (string slice) | Nie (len pozerá) | Fixná |
| `char` | Jeden Unicode znak | Áno | 4 bajty vždy |
```rust
// String — vlastní dáta, môžeš meniť
let mut s: String = String::from("ahoj");
s.push_str(" svet"); // OK — je mut a vlastní dáta
// &str — len referencia, nemôžeš meniť obsah
let slice: &str = "ahoj svet";
// slice.push_str("!"); // CHYBA — &str je len pohľad
// char — jeden znak
let c: char = 'a';
let emoji: char = '🦀'; // aj emoji je jeden char
```
**Analógia:**
- `String` je ako vlastný zošit — píšeš doň, pridávaš strany
- `&str` je ako pohľad cez okno na cudzí zošit — vidíš text, ale nemôžeš ho meniť
- `char` je ako jedno písmeno
### Úlohy 1
**1a.** Ktorý typ použiješ v štruktúre? Prečo?
```rust
struct Kniha {
nazov: ???, // String alebo &str?
}
```
**1b.** Čo je zle? Oprav:
```rust
let s: &str = "ahoj";
s.push_str(" svet");
```
**1c.** Aký je typ každej premennej?
```rust
let a = "ahoj";
let b = String::from("ahoj");
let c = 'a';
let d = &b[..];
let e = b.as_str();
```
---
## Kapitola 2: Vytváranie String
Existuje veľa spôsobov ako vytvoriť String:
```rust
// 1. String::from
let s = String::from("ahoj");
// 2. .to_string() — funguje na čomkoľvek s Display
let s = "ahoj".to_string();
let s = 42.to_string(); // "42"
let s = 3.14.to_string(); // "3.14"
let s = true.to_string(); // "true"
// 3. String::new() — prázdny
let s = String::new(); // ""
// 4. format! — ako println!, ale vráti String
let meno = "Anna";
let vek = 25;
let s = format!("{}{} rokov", meno, vek);
// "Anna má 25 rokov"
// 5. .to_owned() — z &str na String
let slice: &str = "ahoj";
let owned: String = slice.to_owned();
// 6. .into() — Rust odvodí konverziu
let s: String = "ahoj".into();
```
**Ktorý použiť:**
- `String::from("...")` alebo `"...".to_string()` — oboje je rovnaké, použi čo sa ti páči
- `format!()` — keď skladáš z viacerých častí
- `String::new()` — keď budeš pridávať postupne
### Úlohy 2
**2a.** Vytvor String z čísla `42`, z boolu `false`, z float `3.14`. Vypíš ich.
**2b.** Máš premenné `meno: &str` a `vek: u32`. Vytvor String vo formáte `"Meno: Anna, Vek: 25"` pomocou `format!`.
**2c.** Vytvor prázdny String a postupne do neho pridaj 3 slová (použi `push_str`). Výsledok vypíš.
---
## Kapitola 3: Konverzie medzi String a &str
```rust
// &str → String (3 spôsoby, všetky robia to isté)
let slice: &str = "ahoj";
let owned1: String = slice.to_string();
let owned2: String = slice.to_owned();
let owned3: String = String::from(slice);
// String → &str (2 spôsoby)
let owned: String = String::from("ahoj");
let slice1: &str = &owned; // automatická dereferencia
let slice2: &str = owned.as_str(); // explicitné
// String → &str v parametroch funkcie — automaticky!
fn prijmi_str(s: &str) {
println!("{}", s);
}
let owned = String::from("ahoj");
prijmi_str(&owned); // String sa automaticky konvertuje na &str
prijmi_str("ahoj"); // &str funguje priamo
```
**Zlaté pravidlo pre funkcie:**
- Parametre píš ako `&str` — prijmeš aj String aj &str
- Návratové hodnoty a polia v štruktúrach píš ako `String` — vlastníš dáta
```rust
// DOBRÉ — parameter &str prijme oboje
fn pozdrav(meno: &str) -> String {
format!("Ahoj, {}!", meno)
}
pozdrav("Anna"); // &str → OK
pozdrav(&String::from("Boris")); // &String → OK
pozdrav(&"Cyril".to_string()); // &String → OK
// ZLÉ — parameter String núti volajúceho robiť konverziu
fn pozdrav_zle(meno: String) -> String {
format!("Ahoj, {}!", meno)
}
// pozdrav_zle("Anna"); // CHYBA — &str nie je String
pozdrav_zle("Anna".to_string()); // musíš konvertovať
```
### Úlohy 3
**3a.** Napíš funkciu `dlzka(text: &str) -> usize` ktorá vráti dĺžku. Zavolaj ju s `&str` aj so `String`.
**3b.** Napíš funkciu `opakuj(text: &str, n: usize) -> String` ktorá vráti text zopakovaný n-krát.
**3c.** Čo je zle? Oprav:
```rust
fn prvych_5(text: String) -> String {
text[..5].to_string()
}
prvych_5("ahoj svet");
```
---
## Kapitola 4: Modifikácia String
String je meniteľný. Tu sú všetky spôsoby ako ho meniť:
### Pridávanie
```rust
let mut s = String::from("ahoj");
// push_str — pridaj &str na koniec
s.push_str(" svet"); // "ahoj svet"
// push — pridaj jeden char
s.push('!'); // "ahoj svet!"
// + operátor — spája String + &str (konzumuje prvý!)
let a = String::from("ahoj");
let b = String::from(" svet");
let c = a + &b; // c = "ahoj svet", a JE ZKONZUMOVANÝ!
// println!("{}", a); // CHYBA — a bolo presunuté do c
// format! — bezpečná konkatenácia (nekonzumuje nič)
let a = String::from("ahoj");
let b = String::from("svet");
let c = format!("{} {}", a, b); // c = "ahoj svet"
println!("{}", a); // OK — a stále existuje
```
### Mazanie
```rust
let mut s = String::from("ahoj svet");
// clear — vymaž všetko
s.clear(); // ""
let mut s = String::from("ahoj svet");
// truncate — skráť na N bajtov
s.truncate(4); // "ahoj"
let mut s = String::from("ahoj");
// pop — odstráň posledný char, vráti Option<char>
let posledny = s.pop(); // Some('j'), s = "aho"
```
### Nahradenie
```rust
let s = String::from("ahoj svet ahoj");
// replace — nahraď všetky výskyty (vráti nový String)
let novy = s.replace("ahoj", "čau");
// "čau svet čau"
// replacen — nahraď len prvých N výskytov
let novy = s.replacen("ahoj", "čau", 1);
// "čau svet ahoj"
```
**Dôležité:** `replace` vracia nový String, nemení pôvodný.
### Úlohy 4
**4a.** Vytvor String `"Rust je super"`. Pridaj na koniec `" jazyk!"`. Pridaj na koniec `'🦀'`. Vypíš výsledok.
**4b.** Máš String `"ahoj_svet_rust"`. Nahraď všetky `_` medzerou. Vypíš.
**4c.** Máš String. Postupne z neho popuj znaky kým nie je prázdny. Každý vypíš.
**4d.** Čo je zle? Oprav (2 spôsoby):
```rust
let a = String::from("ahoj");
let b = String::from(" svet");
let c = a + &b;
println!("{}", a); // chyba!
```
---
## Kapitola 5: char — jeden znak
`char` v Ruste je 4 bajty a reprezentuje jeden Unicode bod (nie bajt!).
```rust
let c: char = 'a';
let emoji: char = '🦀';
let slovak: char = 'ž';
// Kontroly
c.is_alphabetic(); // true — je písmeno?
c.is_numeric(); // false — je číslica?
c.is_alphanumeric(); // true — písmeno alebo číslica?
c.is_uppercase(); // false
c.is_lowercase(); // true
c.is_whitespace(); // false — je medzera/tab/newline?
c.is_ascii(); // true — je ASCII (0-127)?
// Konverzia veľkosť
c.to_uppercase(); // iterátor! nie char (lebo 'ß' → "SS")
c.to_lowercase(); // iterátor!
c.to_ascii_uppercase(); // char — len pre ASCII znaky
c.to_ascii_lowercase(); // char
// char → String
let s: String = c.to_string(); // "a"
let s: String = String::from(c); // "a"
// char → u32 (Unicode code point)
let kod: u32 = c as u32; // 97
// u32 → char (ak je platný Unicode)
let c: Option<char> = char::from_u32(97); // Some('a')
```
**Dôležité o to_uppercase/to_lowercase:**
```rust
// to_uppercase vráti iterátor, nie char!
// Lebo niektoré znaky sa mapujú na viac znakov: ß → SS
let velke: String = 'a'.to_uppercase().collect(); // "A"
let velke: String = 'ß'.to_uppercase().collect(); // "SS"
// Pre jednoduché ASCII použi to_ascii_uppercase — vráti char
let velke: char = 'a'.to_ascii_uppercase(); // 'A'
```
### Úlohy 5
**5a.** Napíš funkciu `je_samohláska(c: char) -> bool` — true pre a, e, i, o, u (aj veľké). Použi `to_ascii_lowercase()` a `matches!` alebo porovnávanie.
**5b.** Napíš funkciu `pocet_cifier(text: &str) -> usize` — koľko znakov v texte sú číslice. Použi `.chars()` a `.is_numeric()`.
**5c.** Napíš funkciu `velkymi(text: &str) -> String` — celý text veľkými písmenami. Použi `.chars()`, `.to_ascii_uppercase()`, `.collect()`.
**5d.** Čo vráti?
```rust
println!("{}", 'A'.is_uppercase());
println!("{}", '5'.is_numeric());
println!("{}", ' '.is_whitespace());
println!("{}", 'ž'.is_ascii());
println!("{}", 'ž'.is_alphabetic());
```
---
## Kapitola 6: Iterácia cez znaky — chars()
String v Ruste je UTF-8. Jeden znak môže byť 14 bajty. Preto nemôžeš indexovať `s[0]` — nevieš koľko bajtov má znak.
```rust
let text = "ahoj";
// chars() — iterátor cez char hodnoty
for c in text.chars() {
println!("{}", c); // a, h, o, j
}
// Počet znakov
let pocet: usize = text.chars().count(); // 4
// Do Vec<char>
let znaky: Vec<char> = text.chars().collect();
// ['a', 'h', 'o', 'j']
// N-tý znak
let druhy: Option<char> = text.chars().nth(1); // Some('h')
// Prvý znak
let prvy: Option<char> = text.chars().next(); // Some('a')
// Posledný znak
let posledny: Option<char> = text.chars().last(); // Some('j')
```
**Pozor na .len() vs .chars().count():**
```rust
let text = "žaba";
println!("{}", text.len()); // 5 (bajtov! 'ž' = 2 bajty)
println!("{}", text.chars().count()); // 4 (znakov)
// Pre čisto ASCII texty sú rovnaké
let text = "ahoj";
println!("{}", text.len()); // 4
println!("{}", text.chars().count()); // 4
```
### chars() s iterátorovými metódami
```rust
let text = "Ahoj Svet 123";
// filter — len písmená
let pismena: String = text.chars().filter(|c| c.is_alphabetic()).collect();
// "AhojSvet"
// map — na veľké
let velke: String = text.chars().map(|c| c.to_ascii_uppercase()).collect();
// "AHOJ SVET 123"
// any — obsahuje číslicu?
let ma_cislo: bool = text.chars().any(|c| c.is_numeric());
// true
// all — sú všetky písmená?
let vsetky_pismena: bool = text.chars().all(|c| c.is_alphabetic());
// false
// enumerate — index + znak
for (i, c) in text.chars().enumerate() {
println!("{}: {}", i, c);
}
// take — prvých N znakov
let prvych_4: String = text.chars().take(4).collect();
// "Ahoj"
// skip — preskoč prvých N znakov
let od_5: String = text.chars().skip(5).collect();
// "Svet 123"
```
### Úlohy 6
**6a.** Napíš funkciu `prevrat(text: &str) -> String` — obráti text. Použi `.chars().rev().collect()`.
**6b.** Napíš funkciu `je_palindrom(text: &str) -> bool` — true ak sa text rovná sám sebe pozadu. Ignoruj veľkosť písmen.
**6c.** Napíš funkciu `censuruj(text: &str, zakazane: &[char]) -> String` — nahraď zakázané znaky hviezdičkou `'*'`. Použi `.chars().map().collect()`.
**6d.** Napíš funkciu `prvych_n_znakov(text: &str, n: usize) -> String`. Použi `.chars().take(n).collect()`.
**6e.** Napíš funkciu `pocet_slov(text: &str) -> usize`. Použi `.split_whitespace().count()`.
---
## Kapitola 7: Rozdeľovanie reťazcov — split, lines, split_whitespace
### split_whitespace — rozdeľ podľa medzier
```rust
let text = " ahoj svet rust ";
let slova: Vec<&str> = text.split_whitespace().collect();
// ["ahoj", "svet", "rust"] — medzery na okrajoch a duplikáty ignorované
```
### split — rozdeľ podľa oddeľovača
```rust
let text = "anna,boris,cyril";
// Podľa znaku
let mena: Vec<&str> = text.split(',').collect();
// ["anna", "boris", "cyril"]
// Podľa reťazca
let text = "ahoj--svet--rust";
let casti: Vec<&str> = text.split("--").collect();
// ["ahoj", "svet", "rust"]
// splitn — maximálne N častí
let text = "a:b:c:d:e";
let casti: Vec<&str> = text.splitn(3, ':').collect();
// ["a", "b", "c:d:e"] — rozdelí len na prvých 2 dvojbodkách
```
### lines — rozdeľ podľa riadkov
```rust
let text = "prvý riadok\ndruhý riadok\ntretí riadok";
for riadok in text.lines() {
println!("{}", riadok);
}
// prvý riadok
// druhý riadok
// tretí riadok
```
### Úlohy 7
**7a.** Máš CSV riadok `"Anna,25,Bratislava"`. Rozdeľ ho na časti. Vypíš meno, vek, mesto.
**7b.** Napíš funkciu `pocet_slov(text: &str) -> usize`. Použi `split_whitespace`.
**7c.** Máš viacriadkový text. Nájdi najdlhší riadok. Použi `.lines()` a `.max_by_key()`.
**7d.** Máš cestu `"/home/user/docs/file.txt"`. Rozdeľ podľa `/`. Vypíš posledný kúsok (filename).
---
## Kapitola 8: Hľadanie v reťazcoch
```rust
let text = "Ahoj svet, ahoj Rust!";
// contains — obsahuje podreťazec?
text.contains("svet"); // true
text.contains("Python"); // false
// starts_with / ends_with
text.starts_with("Ahoj"); // true
text.ends_with("!"); // true
text.ends_with("Rust"); // false (končí na "!")
// find — index prvého výskytu (v bajtoch!)
text.find("svet"); // Some(5)
text.find("Python"); // None
// rfind — od konca
text.rfind("ahoj"); // Some(11)
// matches — iterátor cez všetky výskyty
let pocet = text.matches("ahoj").count(); // 1 (case-sensitive!)
let pocet = text.to_lowercase().matches("ahoj").count(); // 2
```
### Úlohy 8
**8a.** Napíš funkciu `obsahuje_cislicu(text: &str) -> bool` — true ak text obsahuje aspoň jednu číslicu. Použi `.chars().any()`.
**8b.** Napíš funkciu `pocet_vyskytu(text: &str, hladany: &str) -> usize`. Použi `.matches().count()`.
**8c.** Napíš funkciu `zacina_velkym(text: &str) -> bool` — true ak prvý znak je veľké písmeno.
**8d.** Máš vektor reťazcov. Vyfiltruj len tie, ktoré obsahujú slovo "rust" (case-insensitive).
---
## Kapitola 9: Trimovanie a padding
### trim — odstráň biele znaky z okrajov
```rust
let text = " ahoj svet \n";
text.trim(); // "ahoj svet"
text.trim_start(); // "ahoj svet \n"
text.trim_end(); // " ahoj svet"
// trim_matches — odstráň konkrétne znaky
let text = "---ahoj---";
text.trim_matches('-'); // "ahoj"
let text = "***ahoj***svet***";
text.trim_matches('*'); // "ahoj***svet" (len okraje!)
```
### Padding / zarovnanie (nie metóda, ale format!)
```rust
let meno = "Anna";
// Zarovnanie vpravo (šírka 10)
let s = format!("{:>10}", meno); // " Anna"
// Zarovnanie vľavo
let s = format!("{:<10}", meno); // "Anna "
// Na stred
let s = format!("{:^10}", meno); // " Anna "
// S vlastným znakom
let s = format!("{:*>10}", meno); // "******Anna"
let s = format!("{:-^10}", meno); // "---Anna---"
```
### Úlohy 9
**9a.** Máš vstup od používateľa `" ahoj \n"`. Očisti ho trimom. Potom over, či je "ahoj".
**9b.** Máš vektor mien rôznej dĺžky. Vypíš ich zarovnané vpravo na šírku 15 znakov:
```
Anna
Boris
Cyril
```
**9c.** Napíš funkciu `ocisti(text: &str) -> String` — trim + nahraď viacnásobné medzery jednou. Hint: `split_whitespace().collect::<Vec<&str>>().join(" ")`.
---
## Kapitola 10: Slicing — &str z časti String
Môžeš vziať kúsok reťazca ako &str. Ale **pozor** — indexy sú v bajtoch, nie znakoch!
```rust
let text = "ahoj svet";
// Slice podľa rozsahu bajtov
let slice: &str = &text[0..4]; // "ahoj"
let slice: &str = &text[5..]; // "svet"
let slice: &str = &text[..4]; // "ahoj"
// NEBEZPEČNÉ pre non-ASCII!
let text = "žaba";
// &text[0..1] // PANIC! 'ž' je 2 bajty, toto by rozdelilo uprostred znaku!
// &text[0..2] // OK — "ž"
```
**Bezpečný spôsob pre ľubovoľný text:**
```rust
// Použi chars() namiesto slicingu
fn prvy_znak(text: &str) -> Option<char> {
text.chars().next()
}
fn prvych_n(text: &str, n: usize) -> String {
text.chars().take(n).collect()
}
fn od_znaku_n(text: &str, n: usize) -> String {
text.chars().skip(n).collect()
}
fn podretazec(text: &str, od: usize, do_: usize) -> String {
text.chars().skip(od).take(do_ - od).collect()
}
```
**Kedy je slice bezpečný:**
- Ak vieš, že text je čistý ASCII (anglická abeceda, čísla)
- Ak index získaš z `.find()` (ten vracia bajtový index)
```rust
let text = "ahoj svet rust";
if let Some(pos) = text.find("svet") {
let od_svet: &str = &text[pos..]; // "svet rust" — bezpečné, find vrátil správny index
}
```
### Úlohy 10
**10a.** Máš ASCII text `"Hello World"`. Vyber prvých 5 znakov slicingom. Vyber posledných 5.
**10b.** Napíš funkciu `bezpecne_prvych_n(text: &str, n: usize) -> String` — vráti prvých N znakov bez paniki (aj pre non-ASCII).
**10c.** Máš text. Nájdi pozíciu prvej medzery pomocou `.find(' ')`. Ak existuje, vráť prvé slovo ako &str slice:
```rust
fn prve_slovo(text: &str) -> &str
```
**10d.** Prečo toto panikne? Ako to opravíš?
```rust
let text = "café";
let slice = &text[0..4];
```
---
## Kapitola 11: Parsovanie — z reťazca na iné typy
```rust
// &str / String → číslo (.parse())
let cislo: i32 = "42".parse().unwrap(); // 42
let cislo: f64 = "3.14".parse().unwrap(); // 3.14
let cislo: Result<i32, _> = "nie_cislo".parse(); // Err(...)
// Bezpečné parsovanie
let vstup = "42";
match vstup.parse::<i32>() {
Ok(n) => println!("Číslo: {}", n),
Err(_) => println!("Nie je číslo"),
}
// Alebo s .ok()
let cislo: Option<i32> = vstup.parse().ok();
// číslo → String
let text: String = 42.to_string();
let text: String = format!("{}", 42);
// bool
let b: bool = "true".parse().unwrap(); // true
let b: bool = "false".parse().unwrap(); // false
```
### Úlohy 11
**11a.** Napíš funkciu `parsuj_cisla(text: &str) -> Vec<i32>` — text obsahuje čísla oddelené čiarkami (`"1,2,3,4,5"`). Rozdeľ a sparsuj. Ignoruj neplatné hodnoty.
**11b.** Napíš funkciu `parsuj_csv_riadok(riadok: &str) -> Option<(String, u32, f64)>`:
Vstup: `"Anna,25,1.5"``Some(("Anna".to_string(), 25, 1.5))`
Ak parsovanie zlyhá → None.
**11c.** Máš vstup od používateľa (String). Trim ho, parsuj na u32. Ak sa nepodarí, vyskúšaj f64. Ak ani to, vráť chybu.
---
## Kapitola 12: Pokročilé operácie
### repeat — opakuj reťazec
```rust
let s = "ha".repeat(3); // "hahaha"
let s = "-".repeat(20); // "--------------------"
```
### to_lowercase / to_uppercase
```rust
let text = "Ahoj Svet";
let male: String = text.to_lowercase(); // "ahoj svet"
let velke: String = text.to_uppercase(); // "AHOJ SVET"
// Porovnanie case-insensitive
fn rovnake_ci(a: &str, b: &str) -> bool {
a.to_lowercase() == b.to_lowercase()
}
rovnake_ci("Ahoj", "AHOJ"); // true
```
### char_indices — indexy aj znaky
```rust
let text = "žaba";
// char_indices dáva (bajtový_index, char)
for (i, c) in text.char_indices() {
println!("bajt {}: {}", i, c);
}
// bajt 0: ž
// bajt 2: a (ž zabrala 2 bajty!)
// bajt 3: b
// bajt 4: a
```
### Collect medzi typmi
```rust
// Vec<char> → String
let znaky = vec!['a', 'h', 'o', 'j'];
let text: String = znaky.into_iter().collect();
// "ahoj"
// Vec<&str> → String (s oddeľovačom)
let slova = vec!["ahoj", "svet"];
let text: String = slova.join(" ");
// "ahoj svet"
// Vec<String> → String (s oddeľovačom)
let slova: Vec<String> = vec!["ahoj".into(), "svet".into()];
let text: String = slova.join(", ");
// "ahoj, svet"
// Iterátor &str → String
let text: String = ["ahoj", "svet"].iter().copied().collect::<Vec<&str>>().join(" ");
// S itertools je jednoduchšie:
// use itertools::Itertools;
// let text = ["ahoj", "svet"].iter().join(" ");
```
### Úlohy 12
**12a.** Napíš funkciu `oddelovac(sirka: usize) -> String` — vráti riadok pomlčiek danej šírky.
**12b.** Napíš funkciu `kapitalizuj(text: &str) -> String` — prvé písmeno veľké, zvyšok malé. Hint: `.chars().next()` pre prvé, `.chars().skip(1)` pre zvyšok.
**12c.** Napíš funkciu `snake_to_camel(text: &str) -> String` — preveď `"ahoj_svet_rust"` na `"AhojSvetRust"`. Hint: split podľa `_`, každé slovo kapitalizuj, spoj.
**12d.** Napíš funkciu `je_platny_email(text: &str) -> bool`:
- Obsahuje presne jednu `@`
- Pred `@` je aspoň 1 znak
- Za `@` je aspoň 3 znaky
- Za `@` obsahuje `.`
---
## Kapitola 13: Vzory zo skúšky
### Vzor 1: Display pre štruktúru/enum
```rust
use std::fmt;
enum Stav { Novy, Aktivny, Dokonceny }
impl fmt::Display for Stav {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Stav::Novy => write!(f, "Nový"),
Stav::Aktivny => write!(f, "Aktívny"),
Stav::Dokonceny => write!(f, "Dokončený"),
}
}
}
struct Uloha { nazov: String, stav: Stav }
impl fmt::Display for Uloha {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} [{}]", self.nazov, self.stav)
}
}
// Výstup: "Upratovanie [Nový]"
```
### Vzor 2: Obesenec — zobrazenie skrytého slova
```rust
fn zobraz_slovo(slovo: &str, uhadnute: &HashSet<char>) -> String {
slovo.chars().map(|c| {
if uhadnute.contains(&c) { c } else { '_' }
}).collect()
}
// zobraz_slovo("ahoj", &{'a', 'o'}) → "a_o_"
```
### Vzor 3: Parsovanie vstupu od používateľa
```rust
fn nacitaj_cislo() -> Option<u32> {
let mut vstup = String::new();
std::io::stdin().read_line(&mut vstup).ok()?;
vstup.trim().parse().ok()
}
```
### Vzor 4: CSV / JSON parsovanie
```rust
fn parsuj_knihu(riadok: &str) -> Option<Kniha> {
let casti: Vec<&str> = riadok.split(',').collect();
if casti.len() != 3 { return None; }
let rok: u16 = casti[2].trim().parse().ok()?;
Some(Kniha {
nazov: casti[0].trim().to_string(),
autor: casti[1].trim().to_string(),
rok,
})
}
```
### Úlohy 13
**13a.** Implementuj `Display` pre enum `Priorita { Nizka, Stredna, Vysoka }` — výstup: "Nízka", "Stredná", "Vysoká".
**13b.** Implementuj `Display` pre štruktúru `Zamestnanec { meno: String, pozicia: String, plat: u32 }` vo formáte `"Anna (Programátor) - 3000€"`.
**13c.** Napíš funkciu, ktorá načíta riadok z stdin, trimne ho a vráti. Ak je prázdny po trime, vráti None:
```rust
fn nacitaj_riadok() -> Option<String>
```
**13d.** Napíš funkciu, ktorá sparsuje text `"meno:vek:mesto"` na tuple:
```rust
fn parsuj(text: &str) -> Option<(String, u32, String)>
```
---
## Prehľad konverzií
```
&str ──.to_string()──→ String
&str ──.to_owned()───→ String
&str ──String::from()─→ String
String ──&──────────→ &str
String ──.as_str()──→ &str
char ──.to_string()─→ String
char ──String::from()→ String
&str ──.chars()─────→ Iterator<char>
String ──.chars()───→ Iterator<char>
Iterator<char> ──.collect()──→ String
Vec<char> ──.iter().collect()→ String
&str ──.parse::<T>()──→ Result<T, Error>
T ──.to_string()───────→ String (ak T: Display)
&str ──.as_bytes()────→ &[u8]
```