Hledáme fulltime PHP programátora do ITnetwork týmu - 100% homeoffice, 100% časově flexibilní #bezdeadlinu Mám zájem!
Aktuálně: Postihly zákazy tvou profesi? Poptávka po ajťácích prudce roste, využij slevové akce 50% výuky zdarma!
JavaScript týden

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 875x (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ů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 13 let. Má rád Nirvanu, sushi a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity (19)

 

 

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

Avatar
Pavel Indrák:3.3.2020 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.3.2020 15:37
Avatar
Matěj Klimeš:13.3.2020 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.3.2020 19:40
Avatar
Alesh
Překladatel
Avatar
Odpovídá na Matěj Klimeš
Alesh:13.3.2020 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.3.2020 21:41
 
Odpovědět
13.3.2020 21:40
Avatar
Alesh
Překladatel
Avatar
Odpovídá na Pavel Indrák
Alesh:13.3.2020 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.3.2020 21:53
Avatar
Odpovídá na Matěj Klimeš
Rozbita Zaluzie:25.4.2020 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.4.2020 13:30
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Michal
Člen
Avatar
Michal:3.9.2020 20:32

Ahoj, chtěl bych požádat o radu. Nemůžu přijít na to, kde mám chybu (viz. přiložený zdrojový kód). Pokusil jsem se zadaný text zašifrovat pomocí Morseovky, ale nedaří se mi to. Předem děkuji za radu.

 
Odpovědět
3.9.2020 20:32
Avatar
Michal
Člen
Avatar
Michal:3.9.2020 20:42

Ahoj ještě jednou. Omlouvám se, vidím, že u mého dotazu žádná příloha není. Zkusím tedy druhý pokus :) Jedná se o Lekci9_priklad2 - Morseovku. Nemůžu přijít na to, co je špatně. Předem děkuji za radu.

 
Odpovědět
3.9.2020 20:42
Avatar
Alesh
Překladatel
Avatar
Odpovídá na Michal
Alesh:4.9.2020 20:06

A ten tvůj kód si má ten, kdo ti chce poradit přepsat z obrázku? :-)
Klikni na </>, vloží ti to tag pro vložení kódu a tak svůj kód dej do něj.
[ code]
... tvůj kód ...
[/code]

 
Odpovědět
4.9.2020 20:06
Avatar
Michal
Člen
Avatar
Michal:4.9.2020 22:10

Ahoj, tak třetí pokus :)

package lekce_9_priklad_2;

import java.util.Scanner;
import java.util.Arrays;

public class Lekce_9_priklad_2 {

    public static void main(String[] args) {
        // řetězec, který chceme zakódovat
        Scanner sc = new Scanner(System.in, "Windows-1250");
        System.out.println("Zadej text k zakódování: ");
        String zadani = sc.nextLine().toLowerCase();

        //řetězec se zakódovanou zprávou
        String zprava = "";

        // vzorová pole
        String abeceda = "abcdefghijklmnopqrstuvwxyz";
        String[] morseovka = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....",
        "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-",
        "...-", ".--", "-..-", "-.--", "--.."};

        // iterace jednotlivými znaky zprávy
        for (char c : zadani.toCharArray() ){
            int index = -1;
            for (int i=0; i<abeceda.length(); i++){
                if ((String.valueOf(c)).equals(abeceda.charAt(i))){
                index = i;
                }
            }
                if (index >= 0){
                    zprava = zprava + morseovka[index] + " ";
                }
                else {
                    String znak = "?";
                    zprava = zprava + znak + " ";
                }
        }
        System.out.printf("Zakódovaná zpráva je: %s\n", zprava);
    }

    }
 
Odpovědět
4.9.2020 22:10
Avatar
Alesh
Překladatel
Avatar
Alesh:4.9.2020 23:16

Problém je v této podmínce:

if ((String.valueOf(c)).equals(abeceda.charAt(i)))

Dej tam místo ní toto:

if (c == abeceda.charAt(i))

Jinak teda celkově máš ten kód takovej, no... zbytečně komplikovanej, zkus ho trochu "učesat". ;-)

 
Odpovědět
4.9.2020 23:16
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 62. Zobrazit vše