9. díl - Textové řetězce v Javě do třetice - Split

Java Základní konstrukce Textové řetězce v Javě do třetice - Split

Minule jsme si ukázali, že String je vlastně pole znaků. 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:

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:

-1

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

Split()

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.

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 znaků 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í). 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);
Program dekodér Morseovy abecedy v Javě

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() se potkáme během seriálu 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í sami, 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 sekci se základní strukturou jazyka Java, příště si uvedeme bonusový díl o matematické třídě. 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é články ještě alespoň projet, jedná se přeci jen stále o základní znalosti, které byste měli mít.


 

Stáhnout

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

 

  Aktivity (3)

Článek pro vás napsal David Čápka
Avatar
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 se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.

Jak se ti líbí článek?
Celkem (8 hlasů) :
55555


 


Miniatura
Předchozí článek
Cvičení k 8. lekci Javy
Miniatura
Všechny články v sekci
Základní konstrukce jazyka Java
Miniatura
Následující článek
Cvičení k 9. lekci Javy

 

 

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

Avatar
Jan Vargovský
Redaktor
Avatar
Jan Vargovský:

Se koukni jak funguje regex :)

 
Odpovědět 11.4.2015 17:49
Avatar
roman64
Redaktor
Avatar
roman64:

Dovolím si upozornit na jednu malou nepřesnost u metody SUBSTRING. Druhý parametr není delka (jak bývá obvyklé a lze očekávat), ale index konečného znaku požadovaného sub-řetezce.

Odpovědět  ±0 29.5.2015 17:35
osvícený člověk se učí celý život, hlupákovi stačí hodina
Avatar
Odpovídá na roman64
Tomas Hlinovsky:

já nechápu u toho substringu proc to zleva bere vcetne a zprava jakoby o jedno min..

 
Odpovědět 2.12.2015 22:43
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:

a jak bys chtěl aby to fungovalo?

Odpovědět 3.12.2015 12:32
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
roman64
Redaktor
Avatar
Odpovídá na Tomas Hlinovsky
roman64:

Ahoj. Možná tito bude jasnější s touto iterací:

public static void main(String[] args) {
        String retez = "Ahoj jak se máš?";
        int i;
        for (i=0; i<retez.length();i++)
            System.out.println(retez.substring(0,i));
    }
Odpovědět 3.12.2015 16:46
osvícený člověk se učí celý život, hlupákovi stačí hodina
Avatar
Tomáš Kamlar:

moje verze pro opětovné zakodování zprávy do Moseovy abecedy :)

String zprava2 = "";

       for (char abecedniZnak : zprava.toCharArray())
        {
           int index = -1;
           String znak = " ";
            for (int i = 0; i < abecedniZnaky.length(); i++)
                {
                    if (abecedniZnaky.charAt(i) == abecedniZnak)
                        {
                        index = i;
                        }
                }
            if (index >=0)
                {
                    znak = morseovyZnaky[index];
                }
            zprava2 += znak + " ";
        }
       System.out.printf("Znovu zakodovaná zpráva: %s\n", zprava2);
 
Odpovědět 6.12.2015 16:32
Avatar
Miroslav Bejlek:

Ahoj,
mám dotaz pro spojování řetězců mohu použít buď plus nebo příkaz concat().
String s1, s2, s3;
s3 = s1 + s2; nebo
s3 = s1.concat(s2)

dotaz mám v čem je rozdíl, podle mne je to stejné, pak nechápu proč tu speciální metodu vůbec zaváděli, tak si říkám, že asi nějaký rozdíl v tom bude, prosím řekněte mi jaký :-)

Děkuji :-)

 
Odpovědět 14. září 17:15
Avatar
Dalibor Kužma:

viete mi povedať prečo môj prekladač koktá? Tu je kód:

Scanner sc = new Scanner (System.in, "Windows-1250");
        System.out.println("Vitajte v prekladači do Morseovky!");
        System.out.println("Vložte text na preklad:");
        String s = sc.nextLine();
        String preklad = "";
        String[] abeceda = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
        String[] mAbeceda = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....",
"..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-",
"...-", ".--", "-..-", "-.--", "--.."};
        String[] text = s.split("");
        for ( String aZnak : text){
            String mZnak = "?";
            int index = -1;
            for (int i =0; i < abeceda.length; i++){
                if (abeceda[i].equals(aZnak)){
                    index = i;
                }
            if (index >= 0){
                mZnak = mAbeceda[index];
            }
            preklad += mZnak + " ";
            }

        }
        System.out.printf("Preložený text je: \n %s\n", preklad);
 
Odpovědět 24. listopadu 19:59
Avatar
pocitac770
Redaktor
Avatar
Odpovídá na Dalibor Kužma
pocitac770:

Chyba je v této části kódu, zkus nad tím zapřemýšlet ;)

for (int i =0; i < abeceda.length; i++){
        if (abeceda[i].equals(aZnak)){
                index = i;
        }
        if (index >= 0){
                mZnak = mAbeceda[index];
        }
        preklad += mZnak + " ";
}
 
Odpovědět 24. listopadu 21:59
Avatar
Odpovídá na pocitac770
Dalibor Kužma:

pocitac770 Ďakujem prišiel som na to. Problém bol v zátvorke :).

 
Odpovědět 25. listopadu 22:06
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 27. Zobrazit vše