Lekce 14 - Textové řetězce v Javě do třetice - Split a join
V předešlém cvičení, Řešené úlohy k 13. lekci Javy, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
V dnešním Java tutoriálu si 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 textový řetězec je vlastně pole
Metody na řetězci
Když si vytvoříme libovolnou proměnnou a napíšeme za ni poté tečku, IDE 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 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. Popis toho, co metody dělají a jaké vyžadují parametry, můžeme v IntelliJ vyvolat tím, že najedeme šipkami na metodu, o které chceme vědět více, a stiskneme klávesy Ctrl + Q.
Ř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:
{JAVA_CONSOLE}
System.out.println("Wolfgang Amadeus Mozart".substring(9, 16));
{/JAVA_CONSOLE}
Výstup:
Konzolová aplikace
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:
{JAVA_CONSOLE}
System.out.println("Argentina".compareTo("Barbados"));
{/JAVA_CONSOLE}
Výstup:
Konzolová aplikace
-1
Nyní se pojďme podívat na další metody, které jsou opravdu velmi užitečné.
Metody split()
a
join()
Z předchozích tutoriálů víme, že parsování řetězce 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 zadán jeden delší textový řetězec (řádka souboru nebo řádka 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. 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 join()
se volá přímo na typu String
a
umožňuje nám naopak pole podřetězců spojit oddělovačem do jediného
řetězce. Parametry jsou oddělovač a pole. Výstupem metody je výsledný
řetězec.
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ého řetězce, 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 String sifrovanaZprava = ".-.. . --- -. .- .-. -.. ---"; System.out.printf("Původní zpráva: %s%n", sifrovanaZprava); // řetězec s dekódovanou zprávou String dekodovanaZprava = ""; // vzorová pole String abeceda = "abcdefghijklmnopqrstuvwxyz"; String[] morseovyZnaky = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."};
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 sifrovanaZprava
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 foreach
:
// rozbití řetězce na znaky morseovky String[] znaky = sifrovanaZprava.split(" "); // iterace znaky morseovky for (String morseuvZnak : 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 poli abeceda
, 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:
char abecedniZnak = '?'; int index = -1; for (int i = 0; i < morseovyZnaky.length; i++) { if (morseovyZnaky[i].equals(morseuvZnak)) { index = i; } } if (index >= 0) { // znak nalezen abecedniZnak = abeceda.charAt(index); } dekodovanaZprava += abecedniZnak;
Kód nejprve do abecedního znaku uloží znak ?
, protože se
může stát, že znak v naší sadě nemáme. Následně se pokusíme zjistit
jeho index. Pole v Javě bohužel nedisponuje metodou indexOf()
a
zatím nechceme zabíhat do složitějších datových struktur. Proto si
napíšeme vyhledání typu String
v poli sami, bude to docela
jednoduché.
Vyhledání řetězce v poli
Nejprve nastavíme index na -1
, protože nevíme, zda pole daný
String
(Morseův znak) obsahuje. Následně pole projedeme cyklem a
budeme kontrolovat jednotlivé řetězce s naším stringem (znakem). Již
víme, že k porovnání dvou řetězců musíme použít metodu
equals()
. Pokud řetězce souhlasí, uložíme si aktuální
index.
Pokud jsme znak našli (index >= 0
), dosadíme do proměnné
abecedniZnak
znak z abecedy pod tímto indexem. Nakonec znak
připojíme ke zprávě. Operátor +=
nahrazuje
zprava = zprava + abecedniZnak
.
Na závěr samozřejmě zprávu vypíšeme:
{JAVA_CONSOLE}
// řetězec, který chceme dekódovat
String sifrovanaZprava = ".-.. . --- -. .- .-. -.. ---";
System.out.printf("Původní zpráva: %s%n", sifrovanaZprava);
// řetězec s dekódovanou zprávou
String dekodovanaZprava = "";
// vzorová pole
String abeceda = "abcdefghijklmnopqrstuvwxyz";
String[] morseovyZnaky = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....",
"..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-",
"...-", ".--", "-..-", "-.--", "--.."};
// rozbití řetězce na znaky morseovky
String[] znaky = sifrovanaZprava.split(" ");
// iterace znaky morseovky
for (String morseuvZnak : znaky) {
char abecedniZnak = '?';
int index = -1;
for (int i = 0; i < morseovyZnaky.length; i++) {
if (morseovyZnaky[i].equals(morseuvZnak)) {
index = i;
}
}
// znak nalezen
if (index >= 0) {
abecedniZnak = abeceda.charAt(index);
}
dekodovanaZprava += abecedniZnak;
}
System.out.printf("Dekódovaná zpráva: %s%n", dekodovanaZprava);
{/JAVA_CONSOLE}
Výstup programu:
Konzolová aplikace
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 join()
se setkáme během Java 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 sekvence
\n
, která kdekoli v textu způsobí odřádkování, a poté
\t
, kdy se jedná o tabulátor. Sekvenci \n
do kódu
často nepíšeme a využijeme raději formátový specifikátor
%n
, který způsobí správné odřádkování na specifických
platformách. Pojďme si to vyzkoušet:
{JAVA_CONSOLE}
System.out.println("První řádka\nDruhá řádka");
{/JAVA_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
"\uxxxx"
, 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:
{JAVA_CONSOLE}
System.out.println("Toto je zpětné lomítko: \\");
{/JAVA_CONSOLE}
Stejným způsobem můžeme odescapovat např. uvozovku tak, aby ji Java nechápala jako konec řetězce:
{JAVA_CONSOLE}
System.out.println("Toto je uvozovka: \"");
{/JAVA_CONSOLE}
Vstupy z konzole a polí v okenních aplikacích se samozřejmě escapují
samy, aby uživatel nemohl zadat sekvenci \n
a podobně. V kódu to
má programátor povoleno a musí na to myslet.
Tímto jsme v podstatě zakončili kurz se základní strukturou jazyka Java. V příštích lekcích si uvedeme vícerozměrná pole a matematické operace. Ze základních konstrukcí jazyka nás tu ale již nic nepřekvapí V podstatě bychom se již mohli klidně věnovat i objektům. Doporučujeme však zbylé tutoriály také projít, jedná se přece jen stále o základní znalosti, které bychom měli mít.
V následujícím kvízu, Kvíz - Textové řetězce v Javě, 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 1393x (9.75 kB)
Aplikace je včetně zdrojových kódů v jazyce Java