Lekce 10 - Textové řetězce v Kotlinu do třetice - Split
V předešlém cvičení, Řešené úlohy k 9. lekci Kotlinu, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
Dnes si v Kotlin tutoriálu vysvětlíme další metody na řetězci, které
jsme vám zatím záměrně zatajili, protože jsme nevěděli, že
String
je vlastně pole
Další metody na řetězci
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:

Tutéž nabídku lze vyvolat také stiskem kláves 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 také to, jaké vyžadují parametry.
Řekněme si více o následujících metodách a ukažme si je na jednoduchých příkladech.
Metoda substring()
Vrátí podřetězec od dané počáteční pozice do dané koncové pozice.
{KOTLIN_CONSOLE}
println("Wolfgang Amadeus Mozart".substring(9, 16))
{/KOTLIN_CONSOLE}
Výstup:
Amadeus
Metoda compareTo()
Umožňuje porovnat dva řetězce podle abecedy. Metoda vrací hodnotu
-1
, je-li první řetězec abecedně před řetězcem v parametru,
hodnotu 0
, jsou-li oba řetězce stejné, a hodnotu 1
,
je-li první řetězec abecedně za řetězcem v parametru:
{KOTLIN_CONSOLE}
println("argentina".compareTo("barbados"))
{/KOTLIN_CONSOLE}
Výstup:
-1
Pojďme se nyní podívat na další metody na řetězci, které jsou opravdu velmi užitečné.
Metody split()
a
joinToString()
Z předchozích tutoriálů víme, že parsování řetězce znak po znaku
může být někdy docela složité, přestože jsme prováděli 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 zadaný 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 jistí, ž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)
Význam jednotlivých řetězců:
- 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átorem (oddělovačem) je zde mezera.
- Třetí řetězec je matice o třech sloupcích a třech řádcích. Oddělovačem sloupců je čárka, řádků středník.
Na datovém typu String
můžeme volat metodu
split()
, která bere jako parametr separátor (typu
Char
). Metoda následně původní řetězec rozdělí podle
separátorů 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 i bez parametru, čímž
dojde ke spojení řetězců bez oddělovače.
Jelikož neumíme tvořit objekty (uživatele) 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 dva
ř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
budeme muset přiřadit vzor jejich znaku v morseovce. Písmena můžeme opět
uložit do pouhé proměnné typu String
, protože mají jen jeden
znak. Symboly 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ůžeme samozřejmě přidat i 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 morseovky. Rozdělovat budeme podle znaku mezery. Pole následně
proiterujeme cyklem for
:
// rozbití řetězce na znaky morseovky val znaky = s.split(" ") // iterace znaků morseovky for (morseuvZnak in znaky) { }
Ideálně bychom se měli nějak vypořádat s případy, kdy uživatel zadá
např. více mezer mezi znaky (to uživatelé dělají rádi). Metoda
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 tím
však v tomto tutoriálu zabývat nebudeme.
V cyklu se pokusíme najít aktuálně čtený znak morseovky v poli
morseovyZnaky
. Bude nás zajímat jeho index,
protože když se podíváme na tentýž index v řetězci
abecedniZnaky
, bude tam odpovídající písmeno. To je
samozřejmě způsobeno tím, že jak pole, tak řetězec obsahují stejné
znaky seřazené dle abecedy. Umístěme tedy 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:
{KOTLIN_CONSOLE}
// ř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(".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..")
// rozbití řetězce na znaky morseovky
val znaky = s.split(" ")
// iterace znaky morseovky
for (morseuvZnak in znaky) {
val index = morseovyZnaky.indexOf(morseuvZnak)
// Zkontrolování, že jsme index našli
if (index != -1) {
zprava += abecedniZnaky[index]
}
}
println("Dekódovaná zpráva: $zprava")
{/KOTLIN_CONSOLE}
Výstup:
Původní zpráva: .-.. . --- -. .- .-. -.. --- Dekódovaná zpráva: leonardo
Hotovo! Za úkol máte naprogramovat si program opačný, který naopak
zakóduje řetězec do morseovky. Kód bude velmi podobný. S metodami
split()
a joinToString()
se setká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
, kdy se jedná o tabulátor.
Pojďme si to vyzkoušet:
{KOTLIN_CONSOLE}
println("První řádka\nDruhá řádka")
{/KOTLIN_CONSOLE}
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
představuje kód znaku.
Problém může nastat ve chvíli, kdy chceme napsat samotné lomítko
\
. V tom případě ho musíme tzv. odescapovat:
{KOTLIN_CONSOLE}
println("Toto je zpětné lomítko: \\")
{/KOTLIN_CONSOLE}
Stejným způsobem můžeme odescapovat např. uvozovku tak, aby ji Kotlin nechápal jako konec řetězce:
{KOTLIN_CONSOLE}
println("Toto je uvozovka: \"")
{/KOTLIN_CONSOLE}
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 Kotlinu deklarovat tzv. Raw string. Stačí
obalit text do """
a veškerá zpětná lomítka se chovají jako
obyčejné znaky.
{KOTLIN_CONSOLE}
println("""V tomto stringu nemusím nic escapovat \""")
{/KOTLIN_CONSOLE}
V následujícím kvízu, Kvíz - Textové řetězce v Kotlin, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 46x (7.71 kB)
Aplikace je včetně zdrojových kódů v jazyce Kotlin