Jarní BF Python týden
100% homeoffice, 100% časově flexibilní fulltime programátor pro ITnetwork.cz. #bezdeadlinu Mám zájem!
Využij Jarní akci a získej od nás 50 % bodů navíc zdarma! Zároveň také probíhá Python týden se slevou na e-learning až 80 %

Lekce 9 - Textové řetězce v Kotlin do třetice - Split

V předešlém cvičení Řešené úlohy k 8. lekci Kotlin jsme si procvičili nabyté zkušenosti z předchozích lekcí.

V kurzu jsme si v minulé lekci, Řešené úlohy k 8. lekci Kotlin, ukázali, že String je vlastně pole znaků. Dnes si v Kotlin tutoriálu vysvětlíme další metody na řetězci, které jsem vám záměrně zatajil, protože jsme nevěděli, že String je vlastně pole :)

Na řetězci můžeme používat mnoho metod nebo vlastností, které známe z pole. Jsou to např: first(), last(), indexOf() a další.

Když si vytvoříme libovolnou proměnnou a napíšeme za ni tečku, IntelliJ IDEA nám zobrazí nabídku všech metod a vlastností (a také proměnných, ale k tomu se dostaneme až u objektů), které na ni můžeme volat. Zkusme si to:

Kotlin autocomplete v IntelliJ IDEA

Tu samou nabídku lze vyvolat také stiskem Ctrl + Mezerník v případě, že textový kurzor umístíme na tečku. Samozřejmě to platí pro všechny proměnné i třídy a budeme toho využívat stále častěji. Metody jsou řazené abecedně a můžeme jimi listovat pomocí kurzorových šipek. IntelliJ nám zobrazuje popis metod (co dělají) a jaké vyžadují parametry.

Řekněme si o následujících metodách a ukažme si je na jednoduchých příkladech:

Další metody na řetězci

substring()

Vrátí podřetězec od dané počáteční pozice do dané koncové pozice.

println("Kdo se směje naposled, ten je admin.".substring(13, 21))

Výstup:

naposled

compareTo()

Umožňuje porovnat dva řetězce podle abecedy. Vrací -1 pokud je první řetězec před řetězcem v parametru, 0 pokud jsou stejné a 1 pokud je za ním:

println("akát".compareTo("blýskavice"))

Výstup:

-1

Pojďme se nyní podívat na další metodu na String, která je opravdu velmi užitečná.

split() a joinToString()

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Z předchozího tutoriálu víme, že parsování řetězce znak po znaku může být někdy docela složité a to jsme dělali poměrně jednoduchý příklad. S řetězci se samozřejmě budeme setkávat stále, a to jak na vstupu od uživatele (např. z konzole nebo z polí v okenních aplikacích), tak v souborech TXT a XML. Velmi často máme zadán jeden delší String (řádek souboru nebo řádek konzole), ve kterém je více hodnot, oddělených tzv. separátory, např. čárkou. V tomto případě hovoříme o formátu CSV (Comma-Separated Values, tedy hodnoty oddělené čárkou). Abychom si byli jisti, že víme, o čem hovoříme, ukažme si nějaké ukázkové řetězce:

Jan,Novák,Dlouhá 10,Praha 3,130 00
.. ... .-.. .- -. -.. ... --- ..-. -
(1,2,3;4,5,6;7,8,9)
  • První řetězec je očividně nějaký uživatel, takto bychom mohli např. realizovat uložení uživatelů do CSV souboru, každý na jeden řádek.
  • Druhý řetězec jsou znaky Morseovy abecedy, separátor (oddělovač) je zde mezera.
  • Třetí řetězec je matice o 3 sloupcích a 3 řádcích. Oddělovač sloupců je čárka, řádků středník.

Na String můžeme volat metodu split(), která bere jako parametr separátor (typu Char). Následně původní řetězec rozdělí podle separátoru na pole podřetězců, které vrátí. To nám velmi ulehčí práci při rozdělování hodnot v řetězci.

Metoda joinToString() nám naopak umožňuje pole podřetězců spojit oddělovačem do jediného řetězce, parametr je oddělovač. Výstupem metody je výsledný řetězec. Metodu můžeme zavolat bez parametru a tím dojde ke spojení řetězců bez oddělovače.

Jelikož neumíme tvořit objekty (uživatele) a ani pracovat s vícerozměrnými poli (matice), zkusíme si naprogramovat dekodér zpráv z Morseovy abecedy.

Dekodér Morseovy abecedy

Pojďme si opět připravit strukturu programu. Budeme potřebovat 2 řetězce se zprávou, jeden se zprávou v Morseově abecedě, druhý zatím prázdný, do kterého budeme ukládat výsledek našeho snažení. Dále budeme jako v případě samohlásek potřebovat nějaký vzor písmen. K písmenům samozřejmě vzor jejich znaku v morzeovce. Písmena můžeme opět uložit do pouhé proměnné typu String, protože mají jen jeden znak. Znaky Morseovy abecedy mají již znaků více, ty musíme dát do pole.

Struktura našeho programu by nyní mohla vypadat následovně:

// řetězec, který chceme dekódovat
val s = ".. - -. . - .-- --- .-. -.-"
println("Původní zpráva: $s")
// řetězec s dekódovanou zprávou
var zprava = ""

// vzorová pole
val abecedniZnaky = "abcdefghijklmnopqrstuvwxyz"
val morseovyZnaky = arrayOf(".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..")

Můžete si potom přidat další znaky jako čísla a interpunkční znaménka, my je zde vynecháme. Nyní si řetězec s rozbijeme metodou split() na pole podřetězců, obsahujících jednotlivé znaky morzeovky. Splitovat budeme podle znaku mezery. Pole následně proiterujeme cyklem for:

// rozbití řetězce na znaky morzeovky
val znaky = s.split(" ")

// iterace znaků morzeovky
for (morseuvZnak in znaky) {

}

Ideálně bychom se měli nějak vypořádat s případy, kde uživatel zadá např. více mezer mezi znaky (to uživatelé rádi dělají). split() poté vytvoří o jeden řetězec v poli více, který bude prázdný. Ten bychom měli poté v cyklu detekovat a ignorovat, my se s tím v Kotlin tutoriálu nebudeme zabývat.

V cyklu se pokusíme najít aktuálně čtený znak morzeovky v poli morseovyZnaky. Bude nás zajímat jeho index, protože když se podíváme na ten samý index v řetězci abecedniZnaky, bude tam odpovídající písmeno. To je samozřejmě z toho důvodu, že jak pole tak řetězec obsahují stejné znaky, seřazené dle abecedy. Umístěme do těla cyklu následující kód:

val index = morseovyZnaky.indexOf(morseuvZnak)

// Zkontrolování, že jsme index našli
if (index != -1) {
    zprava += abecedniZnaky[index]
}

Pokusíme se zjistit index morseova znaku. Pokud se to podaří, najdeme v abecedě odpovídající písmeno a to přidáme do zprávy. Operátor += nahrazuje zprava = zprava + abecedniZnaky[index].

Závěrem samozřejmě zprávu vypíšeme:

println("Dekódovaná zpráva: $zprava")

Výstup:

Původní zpráva: .. - -. . - .-- --- .-. -.-
Dekódovaná zpráva: itnetwork

Hotovo! Za úkol máte si naprogramovat program opačný, který naopak zakóduje řetězec do morzeovky, kód bude velmi podobný. Se split() a joinToString() se potkáme během Kotlin kurzu ještě několikrát.

Speciální znaky a escapování

Textový řetězec může obsahovat speciální znaky, které jsou předsazené zpětným lomítkem \. Je to zejména znak \n, který kdekoli v textu způsobí odřádkování a poté \t, kde se jedná o tabulátor.

Pojďme si to vyzkoušet:

println("První řádka\nDruhá řádka")

Znak \ označuje nějakou speciální sekvenci znaků v řetězci a je dále využíván např. k psaní unicode znaku jako \u{xxxx}, kde xxxx je kód znaku.

Problém může nastat ve chvíli, když chceme napsat samotné \, musíme ho tzv. odescapovat:

println("Toto je zpětné lomítko: \\")

Stejným způsobem můžeme odescapovat např. uvozovku tak, aby ji Kotlin nechápal jako konec řetězce:

println("Toto je uvozovka: \"")

Vstupy z konzole a polí v okenních aplikacích se samozřejmě escapují samy, aby uživatel nemohl zadat \n a podobně. V kódu to má programátor povoleno a musí na to myslet.

Raw string

Občas potřebujeme zapsat více zpětných lomítek v jednom textovém řetězci. Kdybychom je všechny escapovali, mohlo by to znepřehlednit náš kód. Kvůli tomuto problému lze v Kotlin deklarovat tzv. Raw string. Stačí obalit text do """ a veškerá zpětné lomítka se chovají jako obyčejné znaky.

println("""V tomto stringu nemusím nic escapovat \""")

Tímto jsme v podstatě zakončili sekci se základní strukturou jazyka Kotlin. V příští lekci, Řešené úlohy k 9. lekci Kotlin, si uvedeme bonusovou lekci o vícerozměrných polích a kurz ještě zakončuje ještě něco o matematické třídě. Ze základních konstrukcí jazyka vás tu ale již nic nepřekvapí :) V podstatě byste již klidně mohli jít i na objekty, doporučují ale zbylé články ještě alespoň projet, jedná se přeci jen stále o základní znalosti, které byste měli mít.

V následujícím cvičení Řešené úlohy k 9. lekci Kotlin si procvičíme nabyté zkušenosti z předchozích lekcí.


 

Stáhnout

Staženo 23x (8.51 kB)
Aplikace je včetně zdrojových kódů v jazyce Kotlin

 

 

Článek pro vás napsal Samuel Kodytek
Avatar
Jak se ti líbí článek?
3 hlasů
Autor se věnuje všem jazykům okolo JVM. Rád pomáhá lidem, kteří se zajímají o programování. Věří, že všichni mají šanci se naučit programovat, jen je potřeba prorazit tu bariéru, který se říká lenost.
Předchozí článek
Řešené úlohy k 8. lekci Kotlin
Všechny články v sekci
Základní konstrukce jazyka Kotlin
Miniatura
Následující článek
Řešené úlohy k 9. lekci Kotlin
Aktivity (12)

 

 

Komentáře

Avatar
gcx11
Redaktor
Avatar
gcx11:28.4.2018 23:26

Možná by stál za zmínku i "raw string"

"""V tomto stringu nemusím nic escapovat \"""
 
Odpovědět
28.4.2018 23:26
Avatar
Samuel Kodytek
Šéfredaktor
Avatar
Odpovídá na gcx11
Samuel Kodytek:29.4.2018 22:30

Přidal jsem to, čekám na schválení :)

Odpovědět
29.4.2018 22:30
There is more than one way to screw it
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Martin Bažant:4. února 14:36

Drobná oprava -

compareTo()

nevrací jen -1 nebo 1. Vrací záporné nebo kladné číslo - a jeho velikost je závislá na tom, o kolik políček je řetězec v abecedě (ASCII tabulce) před/za porovnávaným řetězcem.
Tedy v případě

println("akát".compareTo("ITnetwork"))

bude odpověď 24. (A samozřejmě záleží i na velikosti písmen :-) - pro "iTnetwork" bude odpověď -8)

Editováno 4. února 14:37
 
Odpovědět
4. února 14:36
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 3 zpráv z 3.