From 5182e2f833cfa8a1ce187e4aec1fe6a40c75dde8 Mon Sep 17 00:00:00 2001 From: Priec Date: Sat, 28 Feb 2026 23:21:09 +0100 Subject: [PATCH] str --- JR-priprava-na-skusku6/Cargo.lock | 16 + JR-priprava-na-skusku6/Cargo.toml | 1 + JR-priprava-na-skusku6/src/main.rs | 76 +-- JR-priprava-na-skusku6/src/priprava3.rs | 94 ++- priprava/rust_priprava8.md | 844 ++++++++++++++++++++++++ 5 files changed, 945 insertions(+), 86 deletions(-) create mode 100644 priprava/rust_priprava8.md diff --git a/JR-priprava-na-skusku6/Cargo.lock b/JR-priprava-na-skusku6/Cargo.lock index d923f33..26657a1 100644 --- a/JR-priprava-na-skusku6/Cargo.lock +++ b/JR-priprava-na-skusku6/Cargo.lock @@ -6,10 +6,26 @@ version = 4 name = "JR-priprava-na-skusku6" version = "0.1.0" dependencies = [ + "itertools", "serde", "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]] name = "itoa" version = "1.0.17" diff --git a/JR-priprava-na-skusku6/Cargo.toml b/JR-priprava-na-skusku6/Cargo.toml index 8d9af04..32fdbee 100644 --- a/JR-priprava-na-skusku6/Cargo.toml +++ b/JR-priprava-na-skusku6/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" edition = "2024" [dependencies] +itertools = "0.14.0" serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" diff --git a/JR-priprava-na-skusku6/src/main.rs b/JR-priprava-na-skusku6/src/main.rs index 59b444b..ce6f6ed 100644 --- a/JR-priprava-na-skusku6/src/main.rs +++ b/JR-priprava-na-skusku6/src/main.rs @@ -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() { - priprava3::spusti(); - match std::fs::read_to_string("subor.txt") { - Ok(x) => print!("{x}"), - Err(y) => print!("{y}"), - }; -} + // priprava3::spusti(); -fn nacitaj_a_parsuj(cesta: &str) -> Result> { - let obsah = match std::fs::read_to_string(cesta) { - Ok(s) => s, - Err(e) => return Err(Box::new(e)), - }; - let cislo = match obsah.trim().parse::() { - Ok(n) => n, - Err(e) => return Err(Box::new(e)), - }; - Ok(cislo) -} - -fn nacitaj_a_parsuj2(cesta: &str) -> Result> { - let obsah = std::fs::read_to_string(cesta)?; - let cislo = obsah.trim().parse::()?; - Ok(cislo) -} - -fn prvy_sused(vektor: &[i32], index: usize) -> Option { - 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, + let input = vec![1, 3, 2, 1, 2, 3, 1, 1, 2]; + let sorted = input.iter().sorted().collect::>(); + let mut vys: HashMap = HashMap::new(); + for (i, j) in &sorted.into_iter().chunk_by(|&x| x) { + // vys.insert(i, j); + print!("{:#?}", i); + let r = j.cloned().collect::>(); + vys.insert(*i, r.len()); + print!("{:#?}", r); } + + println!("{:#?}", vys) } - -fn prvy_sused2(vektor: &[i32], index: usize) -> Option { - 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> { - let nacitane = std::fs::read_to_string(cesta).ok()?; - let vec = serde_json::from_str::>(nacitane.as_str()); - Some(vec.ok()?) -} - - - diff --git a/JR-priprava-na-skusku6/src/priprava3.rs b/JR-priprava-na-skusku6/src/priprava3.rs index e55cd5e..22d65c8 100644 --- a/JR-priprava-na-skusku6/src/priprava3.rs +++ b/JR-priprava-na-skusku6/src/priprava3.rs @@ -2,34 +2,74 @@ use std::fmt; use std::collections::HashMap; pub fn spusti() { - let mut mapa: HashMap = HashMap::new(); - // Vloženie - mapa.insert("Anna".to_string(), 25); - mapa.insert("Boris".to_string(), 30); - - // Čítanie — vráti Option<&V> - let vek: Option<&i32> = mapa.get("Anna"); // Some(&25) - let vek: Option<&i32> = mapa.get("Cyril"); // None - - // 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) - } + let z1 = Zamestnanec::new("Meno", "1 oddelenie", 1000); + let z2 = Zamestnanec::new("Meno2", "2 oddelenie", 1300); + let z3 = Zamestnanec::new("Meno3", "2 oddelenie", 1100); + let z: &[Zamestnanec] = &[z1, z2, z3]; + // celkovy_plat_na_oddeleni(z); + // pocet_na_oddeleni(z); + // vypis_statistiky2(z); + oddelenie_s_najvyssim_platom(z); } #[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 { + let mut mapa: HashMap = 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 { + let mut mapa: HashMap = 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 = 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 { + 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, + } +} diff --git a/priprava/rust_priprava8.md b/priprava/rust_priprava8.md new file mode 100644 index 0000000..9d6fb9b --- /dev/null +++ b/priprava/rust_priprava8.md @@ -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!("{} má {} 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 +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::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ť 1–4 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 +let znaky: Vec = text.chars().collect(); +// ['a', 'h', 'o', 'j'] + +// N-tý znak +let druhy: Option = text.chars().nth(1); // Some('h') + +// Prvý znak +let prvy: Option = text.chars().next(); // Some('a') + +// Posledný znak +let posledny: Option = 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::>().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 { + 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 = "nie_cislo".parse(); // Err(...) + +// Bezpečné parsovanie +let vstup = "42"; +match vstup.parse::() { + Ok(n) => println!("Číslo: {}", n), + Err(_) => println!("Nie je číslo"), +} + +// Alebo s .ok() +let cislo: Option = 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` — 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 → 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 (s oddeľovačom) +let slova: Vec = vec!["ahoj".into(), "svet".into()]; +let text: String = slova.join(", "); +// "ahoj, svet" + +// Iterátor &str → String +let text: String = ["ahoj", "svet"].iter().copied().collect::>().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) -> 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 { + 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 { + 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 +``` + +**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 +String ──.chars()───→ Iterator + +Iterator ──.collect()──→ String +Vec ──.iter().collect()→ String + +&str ──.parse::()──→ Result +T ──.to_string()───────→ String (ak T: Display) + +&str ──.as_bytes()────→ &[u8] +```