BF Summer sales
Pouze tento týden sleva až 80 % na HTML & CSS a JavaScript
80 % bodů zdarma na online výuku díky naší Letní akci!

Lekce 9 - Textové řetězce v Javě do třetice - Split a join

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

Dnes si 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 :)

Když si vytvoříme libovolnou proměnnou a napíšeme za ni poté tečku, zobrazí nám NetBeans 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:

Metody na textovém řetězci string v NetBeans

Tu samou nabídku lze vyvolat také stiskem 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 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.

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

Výstup:

Konzolová aplikace
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:

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

Výstup:

Konzolová aplikace
-1

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

split() a join()

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 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 (řá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)

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 Stringu 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 morzeovce. Písmena můžeme opět uložit do pouhého Stringu, 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 s = ".. - -. . - .-- --- .-. -.-";
System.out.printf("Původní zpráva: %s\n", s);
// řetězec s dekódovanou zprávou
String zprava = "";

// vzorová pole
String abecedniZnaky = "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 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 foreach:

// rozbití řetězce na znaky morzeovky
String[] znaky = s.split(" ");

// iterace znaky morzeovky
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 morzeovky v poli morseovyZnaky. Bude nás zajímat jeho index, protože když se podíváme na ten samý index v poli 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:

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 = abecedniZnaky.charAt(index);
}
zprava += abecedniZnak;

Kód nejprve do abecedního znaku uloží '?', 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í Stringu v poli sami, bude to docela jednoduché.

Nejprve nastavíme index na -1, protože nevíme, jestli pole daný String (morzeův znak) obsahuje. Následně pole projedeme cyklem a budeme kontrolovat jednotlivé Stringy 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 abecedniZnak znak z abecedních znaků 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:

System.out.printf("Dekódovaná zpráva: %s\n", zprava);

Konzolová aplikace
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 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 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:

System.out.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 "\uxxxx", kde xxxx je kód znaku.

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

System.out.println("Toto je zpětné lomítko: \\");

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

System.out.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.

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čují 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 cvičení, Řešené úlohy k 9. lekci Javy, si procvičíme nabyté zkušenosti z předchozích lekcí.


 

Stáhnout

Staženo 853x (20.2 kB)
Aplikace je včetně zdrojových kódů v jazyce java

 

Předchozí článek
Řešené úlohy k 8. lekci Javy
Všechny články v sekci
Základní konstrukce jazyka Java
Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
22 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity (18)

 

 

Komentáře
Zobrazit starší komentáře (47)

Avatar
Marek Hollý
Člen
Avatar
Marek Hollý:28.11.2018 16:44

Ahoj prosím vás v tej opačnej morzeovke je nutné dávať znaky abecedy do poľa stringov?

 
Odpovědět
28.11.2018 16:44
Avatar
Nessay
Člen
Avatar
Nessay:25.1.2019 14:45
System.out.println("Prosim zadaj spravu, ktoru zasifrujem do morzeovky:");
       String in = sc.nextLine();
       in = in.toLowerCase();
      String[] morseovyZnaky = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."};
       String morzeovka = "";
       String[] slova = in.split(" ");                                   // spravu rozdelime do slov
       for (String slovo : slova){
           String morzeovZnak = "?";
           int index = -1;
           int dlzkaSlova = 0 ;                                          // slova rozdelime do pismen a tie na ASCII hodnotu
               for (int i = 0; i < slovo.length(); i++){
                   dlzkaSlova ++;
               char pismenko = slovo.charAt(i);
               int o = (char)pismenko;
               index = o - 97;                                             // 97 je ASCII hodnota 'a' a pole zacina indexom '0'
               morzeovZnak = morseovyZnaky[index];
               morzeovka += morzeovZnak;
               if (dlzkaSlova == slovo.length()){
                   morzeovka += " ";
               }
           }
        }
        System.out.printf("Tvoja sprava v morzeovke vyzera takto: \"%s\"\n", morzeovka);

Da sa prosim vas "medzerovat" slova v sprave aj inak? (viem mohlo byt 2.
for (char pismenko : slovo.toCharA­rray())

 
Odpovědět
25.1.2019 14:45
Avatar
Matěj Bína
Člen
Avatar
Matěj Bína:23.3.2019 17:57

OK, takže... zpětnej překladač mi dělal blbiny kvůli tomu, že jsem se nemorseovské znaky snažil ošetřit přidáním

else {
        morseuvZnak = "?";
}

Prostě buď vypsal jedno písmeno a samý otazníky, nebo rovnou samý otazníky (proč překládal správně jenom písmeno z jsem se nikdy nedopátral).
Pak jsem viděl kód dommynyka o pár komentů výš, a když jsem za svůj kód u if přidal break; šlape to jak po másle.
Takže... je u if / else nutné používat break; nebo je možný, že chyba byla někde jinde?

 
Odpovědět
23.3.2019 17:57
Avatar
zitekv
Člen
Avatar
zitekv:23.3.2019 22:29

Když sem nevložíš kód toho cyklu, co ti dělá problémy, tak to bez věštecké koule nejde poradit.
Naštěstí jednu mám :-)
Podle všeho v cyklu projíždíš celou abecedu a pokud je shoda přiřadíš písmeno, ale cyklus nezastavíš ( a to právě udělá ten break - tzn. s if else to nemá žádnou souvislost) a další kontrolou ti to zase vloží otazník. Akorát z je na konci, tak to tam zůstane.
Je to tak?

 
Odpovědět
23.3.2019 22:29
Avatar
Marcel Mares
Člen
Avatar
Marcel Mares:22.8.2019 19:14

jaký odstrašující příklad, vždyť to máte dobře, jenom jste si ty poslední dva řádky nevyndala z těch cyklů, ale sama jste si toho za chvíli všimla a váš kód jste podle mě hezky zjednodušila tím, že i tu naši abecedu jste dala do pole stringů a odpadlo převádění mezi int a char a díky .toLowerCase a .trim na vstupu uživatele odpadly problémy s velkými písmeny a mezerami,
za mě určitě palec nahoru

 
Odpovědět
22.8.2019 19:14
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Pavel Indrák:3. března 15:37

Mohl by mi prosím někdo napsat příklad použití metody Join()?? Děkuji. Použití metody split() chápu včetně syntaxe. Nicméně bych potřeboval vidět i praktický příklad toho Joinu, kvůli správné syntaxi.

 
Odpovědět
3. března 15:37
Avatar
Matěj Klimeš:13. března 19:40

Chtěl bych se Vás všech zeptat, co mám špatně. Snažil jsem se vytvořit program, který normální zprávu zašifruje do morseovky, jenže při vypsání zakódovaného textu se vypíše jen otazník. Řekne mi někdo, kde mám chybu? Předem díky.

 
Odpovědět
13. března 19:40
Avatar
Alesh
Překladatel
Avatar
Odpovídá na Matěj Klimeš
Alesh:13. března 21:40

Předně kód nedávej jako obrázek, ale do tagu pro kód, tj. klikni na "</>" nebo Ctrl + K
Chyba je určitě v podmínce uvnitř for cyklu, kde procházíš jednotlivé kódy pro písmena a porovnáváš je s otazníkem (proměnná morseuvZnak), což nebude nikdy splněno, tudíž v proměnné morseuvZnak zůstane ten otazník.

Editováno 13. března 21:41
 
Odpovědět
13. března 21:40
Avatar
Alesh
Překladatel
Avatar
Odpovídá na Pavel Indrák
Alesh:13. března 21:53

Tak máš to vlastně "reverzní" metodu k tomu split. Split to rozseká podle toho oddělovače do pole. Join naopak spojí pole do textového řetězce se zvoleným oddělovačem. Např.:

String kamaradi[] = {"Pavel", "Lojza", "Pepík"};
System.out.println("Moji kamarádi jsou: " + String.join(", ", kamaradi));
//Moji kamarádi jsou: Pavel, Lojza, Pepík
 
Odpovědět
13. března 21:53
Avatar
Odpovídá na Matěj Klimeš
Rozbita Zaluzie:25. dubna 13:30

Matěj Klimeš problém je v tom že pří dekódování morseovky napíšeš několik kódů oddělených mezerou např.: ".- -- -.. ." a od toho je ta metoda split() ale protože pří zakódování do morseovky píšeš slova která jsou z písmenek bez oddělení mezer a proto musíš místo metody split() použít metodu toCharArray() který rozdělí celý string na char neboli jednotné znaky které pak projdou cyklem a pokud je v cyklu vše dobře měly by se předělat na morseovku.. a ještě něco u řádku který pak přidává jednotné morseovy znaky předělej kód tak aby se do konečné zprávy přidal jeden znak + mezera (aby ne konci byly znaky oddělené) a poté by mělo vše fungovat :) kdyby ne ještě napiš

 
Odpovědět
25. dubna 13:30
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 10 zpráv z 57. Zobrazit vše