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é jsem vám záměrně zatajil, 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, zobrazí nám IDE 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:
Tu samou 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. NetBeans nám navíc zobrazuje i popis metod (co dělají) a jaké vyžadují parametry. Stejný popis 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 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. Vrací hodnotu
-1
, pokud je první řetězec před řetězcem v parametru, hodnotu
0
, pokud jsou stejné a hodnotu 1
, pokud je za
ním:
{JAVA_CONSOLE}
System.out.println("Argentina".compareTo("Barbados"));
{/JAVA_CONSOLE}
Výstup:
Konzolová aplikace
-1
Pojďme se nyní podívat na další metody, které jsou opravdu velmi užitečné.
Metody split()
a
join()
Z předchozího tutoriálu víme, že parsování řetězce 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ší 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 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)
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á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 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) 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 morseovce. Písmena můžeme opět uložit do pouhého řetězce, 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 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ůžete si potom přidat 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, kde uživatel zadá
např. více mezer mezi znaky (to uživatelé rádi dělají). 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 s tím v
tutoriálu nebudeme zabývat.
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 ten samý index v poli abeceda
, 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:
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 nemá metodu indexOf()
a zatím
nechci zabíhat do složitějších datových struktur. Napíšeme si tedy
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, jestli 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 musíme k porovnání dvou řetězců 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
.
Závěrem 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 si naprogramovat program opačný, který naopak
zakóduje řetězec do morseovky, kód bude velmi podobný. S metodami
split()
a join()
se potká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
, kde 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
je kód znaku.
Problém může nastat ve chvíli, když chceme napsat samotné lomítko
\
, musíme ho 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 vás tu ale již nic nepřekvapí V podstatě byste již klidně mohli jít i na objekty, doporučuji ale zbylé tutoriály 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 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 1275x (9.75 kB)
Aplikace je včetně zdrojových kódů v jazyce Java