Lekce 11 - Textové řetězce ve VB.NET do třetice - Split a Join
V předešlém cvičení, Řešené úlohy k 10. lekci VB.NET, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
Dnes si ve Visual Basic .NET tutoriálu 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
Na řetězci můžeme používat mnoho metod, které známe z pole. Jsou to
např: First()
, Last()
, IndexOf()
a
další.
Když si vytvoříte libovolnou proměnnou a napíšete za ni poté tečku, zobrazí vám Visual Studio nabídku všech metod a vlastností (a také proměnných, ale k tomu se dostaneme až u objektů), které na ni můžete volat. Tomuto nástroji se říká IntelliSense a zpříjemní vám práci s kódem, který za vás doplňuje. Zkusme si to:

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. VS nám zobrazuje popis metod (co dělají) a jaké mají 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
Insert()
Vloží podřetězec do řetězce na určitou pozici. Parametry jsou pozice v řetězci a podřetězec.
{VBNET_CONSOLE} Console.WriteLine("Punk's dead".Insert(7, "not ")) {/VBNET_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
Výstup:
Konzolová aplikace
Punk's not dead
Remove()
Vymaže znaky od dané pozice do konce. Parametrem je číselná pozice. Můžeme zadat druhý parametr, kterým je počet znaků, které chceme vymazat.
{VBNET_CONSOLE} Console.WriteLine("Michael Jackson".Remove(7, 5)) {/VBNET_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
Výstup:
Konzolová aplikace
Michaelson
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.
{VBNET_CONSOLE} Console.WriteLine("Wolfgang Amadeus Mozart".Substring(9, 7)) {/VBNET_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
Výstup:
Konzolová aplikace
Amadeus
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:
{VBNET_CONSOLE} Console.WriteLine("Argentina".CompareTo("Barbados")) {/VBNET_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
Výstup:
Konzolová aplikace
-1
Pojďme se nyní podívat na 2 další metody na typu String
,
které jsou opravdu velmi užitečné.
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ší 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 proměnných typu String
můžeme volat metodu
Split()
, která bere jako parametr separátor (Char
),
případně dokonce pole 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 jako
pouhý String
, 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 Dim s As String = ".-.. . --- -. .- .-. -.. ---" Console.WriteLine("Původní zpráva: {0}", s) ' řetězec s dekódovanou zprávou Dim zprava As String = "" ' vzorová pole Dim abecedniZnaky As String = "abcdefghijklmnopqrstuvwxyz" Dim morseovyZnaky() As String = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."}
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 řetězců, obsahujících jednotlivé
znaky morzeovky. Splitovat budeme podle znaku mezery. Pole následně
proiterujeme cyklem For Each
:
' rozbití řetězce na znaky morzeovky Dim znaky() As String = s.Split(" ") ' iterace znaky morzeovky For Each morseuvZnak As String In znaky Next
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:
Dim abecedniZnak As Char = "?" Dim index As Integer = Array.IndexOf(morseovyZnaky, morseuvZnak) If index >= 0 Then ' znak nalezen abecedniZnak = abecedniZnaky(index) End If 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 a přidáme
ReadKey()
:
{VBNET_CONSOLE} ' řetězec, který chceme dekódovat Dim s As String = ".-.. . --- -. .- .-. -.. ---" Console.WriteLine("Původní zpráva: {0}", s) ' řetězec s dekódovanou zprávou Dim zprava As String = "" ' vzorová pole Dim abecedniZnaky As String = "abcdefghijklmnopqrstuvwxyz" Dim morseovyZnaky() As String = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."} ' rozbití řetězce na znaky morzeovky Dim znaky() As String = s.Split(" ") ' iterace znaky morzeovky For Each morseuvZnak As String In znaky Dim abecedniZnak As Char = "?" Dim index As Integer = Array.IndexOf(morseovyZnaky, morseuvZnak) If index >= 0 Then ' znak nalezen abecedniZnak = abecedniZnaky(index) End If zprava &= abecedniZnak Next Console.WriteLine("Dekódovaná zpráva: {0}", zprava) Console.ReadKey() {/VBNET_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
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 morzeovky, kód bude velmi podobný. Se
Split()
a Join()
se potkáme během seriálu ještě
několikrát.
Speciální znaky a escapování
Textový řetězec může obsahovat více řádků nebo třeba tabulátory.
Speciálních znaků je ještě více, ale nebudeme si je zde všechny
zmiňovat. Nový řádek do řetězce vložíme pomocí konstanty
vbCrLf
a tabulátor pomocí vbTab
. Pojďme si to
vyzkoušet:
{VBNET_CONSOLE} 'První možnost Console.WriteLine("První řádka{0}Druhá řádka", vbCrLf) 'Druhá možnost Console.WriteLine("První řádka" & vbCrLf & "Druhá řádka") 'Obě fungují a dělají to samé. Console.ReadKey() {/VBNET_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
VB.NET do textu vloží 2 znaky a to CR a LF. Pokud jste se zajímali o ASCII
tabulku, tak víte, že to jsou právě znaky ASCII, konkrétně CR má číslo
13
a LF 10
. Ukončování řádků těmito dvěma
znaky má původ ve starých tiskárnách, kde jeden znak označoval návrat
tiskové hlavy (Carriage Return) na začátek řádku a druhý posun papíru
dolů (Line Feed). Úplně to stejné se stane pokud napíšete:
{VBNET_CONSOLE} Console.WriteLine("První řádka{0}Druhá řádka", Chr(13) & Chr(10)) 'Druhá možnost Console.WriteLine("První řádka" & Chr(13) & Chr(10) & "Druhá řádka") 'Obě fungují a dělají to samé. Console.ReadKey() {/VBNET_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
Pokud byste někdy potřebovali dvojité uvozovky v řetězci, napíšete je jako dvoje dvojité uvozovky. VB.NET si je tak nesplete s koncem řetězce. Takovéto technice odstranění speciálního významu nějakého znaku se obecně říká escapování.
{VBNET_CONSOLE} Console.WriteLine("Toto je uvozovka: """) {/VBNET_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
V následujícím kvízu, Kvíz - Textové řetězce ve VB.NET, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.