NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Lekce 10 - Textové řetězce v Dartu do třetice - split a join

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

V on-line Dart kurzu jsme si v minulé lekci, Řešené úlohy k 9. lekci Dartu, ukázali, že String je vlastně seznam 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ě něco jako seznam :)

Na řetězci můžeme používat mnoho metod a vlastností, které známe ze seznamů. Jsou to např: contains(), indexOf(), substring() namísto sublist(), length a další.

Když si vytvoříme libovolnou proměnnou a napíšeme za ni tečku, IntelliJ IDEA 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. Napovídání nám zpříjemní práci s kódem, který za nás doplňuje. Zkusme si to:

Doplňování kódu v programovacím jazyce Dart - Základní konstrukce jazyka Dart

Tu samou nabídku lze vyvolat také stiskem CTRL + Mezerník v případě, že textový 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 a vlastnosti jsou řazené podle důležitosti a můžeme jimi listovat pomocí kurzorových šipek. IDEA nám zobrazuje jaké vyžadují parametry, co vracejí a můžeme si nechat zobrazit i popis (co dělají) pomocí CTRL + Q.

Ř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é pozice do konce řetězce. Můžeme zadat druhý parametr, kterým je délka podřetězce.

print('Kdo se směje naposled, ten je admin.'.substring(13, 13 + 8));

Výstup programu:

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:

print('akát'.compareTo('blýskavice'));

Výstup programu:

Konzolová aplikace
-1

startsWith()

Vrátí logickou hodnotu podle toho, jestli řetězec začíná podle vzoru v parametru.

print('Hajej, hajej, pacholátko, houpe tě tvá maminka.'.startsWith('Hajný'));
print('Hajej, hajej, pacholátko, houpe tě tvá maminka.'.startsWith('Hajej'));
print('Hajej, hajej, pacholátko, houpe tě tvá maminka.'.startsWith('HAJEJ'));

Výstup programu:

Konzolová aplikace
false
true
false

endsWith()

print('Paci, paci, pacičky, máma koupí botičky.'.endsWith('botasky.'));
print('Paci, paci, pacičky, máma koupí botičky.'.endsWith('botičky.'));
print('Paci, paci, pacičky, máma koupí botičky.'.endsWith('BOTIČKY.'));

Výstup programu:

Konzolová aplikace
false
true
false

Vrátí logickou hodnotu podle toho, jestli řetězec končí podle vzoru v parametru.

Pojďme se nyní podívat na 2 další metody na Stringu, které jsou opravdu velmi užitečné.

split() a join()

Z předchozí lekce Dartu 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 např. v souborech TXT a XML. Velmi často máme zadán jeden delší String (řádek souboru nebo řádek 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, řádek středník.

Na Stringu můžeme volat metodu split(), která bere jako parametr separátor (oddělovač). 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 nevolá přímo na typu String, ale na seznamu (jakéhokoli typu), a umožňuje nám naopak seznam spojit oddělovačem do jediného řetězce, parametrem je oddělovač. Výstupem metody je výsledný řetězec. Pokud je prvkem seznamu jiný datový typ než String, provede se jeho konverze na ř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 seznamu.

Struktura našeho programu by nyní mohla vypadat následovně:

// řetězec, který chceme dekódovat
String s = '.. - -. . - .-- --- .-. -.-';
print('Původní zpráva: $s');
// řetězec s dekódovanou zprávou
String zprava = '';

// vzorové abecedy
String abecedniZnaky = 'abcdefghijklmnopqrstuvwxyz';
List<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 seznam podřetězců, obsahujících jednotlivé znaky morzeovky. Splitovat budeme podle znaku mezery. Pole následně proiterujeme metodou forEach():

// rozbití řetězce na znaky morzeovky
List<String> znaky = s.split(' ');

// iterace znaků morzeovky
znaky.forEach((String morseuvZnak) {

});

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 seznamu 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:

String abecedniZnak = '?';
int index = morseovyZnaky.indexOf(morseuvZnak);
if (index >= 0) // znak nalezen
    abecedniZnak = abecedniZnaky[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. Pokud se to podaří, 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:

print('Dekódovaná zpráva: $zprava');

Výstup programu:

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 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:

print('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, což je ekvivalentní \u{xxxx}, kde xxxx je kód znaku.

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

print('Toto je zpětné lomítko: \\');

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

print("Toto je uvozovka: \"");

Problém může být, když chceme zapsat nějakou delší cestu k souboru, kde máme velké množství zpětných lomítek. I na to Dart myslí a zavedli modifikátor r ("raw" string), díky kterému Dart automaticky escapuje celý námi napsaný řetězec v kódu (tedy každý znak ztratí svůj speciální význam):

print(r'D:\git\itnetwork');
print(r'V proměnné a je obsah $a.');

Vstupy z proměnných a polí se samozřejmě escapují samy, aby uživatel nemohl zadat $a a podobně. V kódu to má programátor povoleno a musí na to myslet.

V příští lekci, Řešené úlohy k 10. lekci Dartu, se podíváme na vnořené seznamy a jak s nimi pracovat.

V následujícím cvičení, Řešené úlohy k 10. lekci Dartu, si procvičí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 5x (2.41 kB)
Aplikace je včetně zdrojových kódů v jazyce Dart

 

Předchozí článek
Řešené úlohy k 9. lekci Dartu
Všechny články v sekci
Základní konstrukce jazyka Dart
Přeskočit článek
(nedoporučujeme)
Řešené úlohy k 10. lekci Dartu
Článek pro vás napsal Honza Bittner
Avatar
Uživatelské hodnocení:
1 hlasů
FIT ČVUT alumnus :-) Sleduj mě na https://twitter.com/tenhobi a ptej se na cokoli na https://github.com/tenhobi/ama.
Aktivity