Lekce 10 - Textové řetězce ve VB.NET podruhé - Práce se znaky
V minulé lekci, Nejčastější chyby VB.NET nováčků - Umíš pojmenovat proměnné?, jsme si ukázali nejčastější chyby začátečníků ve VB.NET ohledně pojmenování proměnných.
Pokud jste vycítili nějakou podobnost mezi polem a textovým řetězcem,
tak jste vycítili správně. Pro ostatní může být překvapením, že
String
je v podstatě pole znaků (prvků typu
Char
) a můžeme s ním i takto pracovat.
Nejprve si v dnešním Visual Basic .NET tutoriálu vyzkoušíme, že to všechno funguje. Rozcvičíme se na jednoduchém vypsání znaku na dané pozici:
{VBNET_CONSOLE}
Dim s As String = "VB.NET"
Console.WriteLine(s)
Console.WriteLine(s(1))
Console.ReadKey()
{/VBNET_CONSOLE}
Výstup:
Konzolová aplikace
VB.NET
B
Vidíme, že můžeme ke znakům v řetězci přistupovat přes kulatou závorku, jako tomu je i u pole. Zklamáním může být, že znaky na dané pozici jsou ve VB.NET read-only, nemůžeme tedy napsat:
' Tento kód nefunguje Dim s As String = "VB.NET" s(1) = "C" Console.WriteLine(s) Console.ReadKey()
Samozřejmě to jde udělat jinak, později si to ukážeme, zatím se budeme věnovat pouze čtení jednotlivých znaků.
Analýza výskytu znaků ve větě
Napišme si jednoduchý program, který nám analyzuje zadanou větu. Bude
nás zajímat počet samohlásek, souhlásek a počet nepísmenných znaků
(např. mezera nebo !
).
Daný textový řetězec si nejprve v programu zadáme napevno, abychom ho
nemuseli při každém spuštění psát. Až bude program hotový, nahradíme
ho Console.ReadLine()
. Řetězec budeme projíždět cyklem po
jednom znaku. Rovnou zde říkám, že neapelujeme na rychlost programu a budeme
volit názorná a jednoduchá řešení.
Nejprve si připravme kód, definujme si samohlásky a souhlásky. Počet nepísmen nemusíme počítat, bude to délka řetězce mínus samohlásky a souhlásky. Abychom nemuseli řešit velikost písmen, celý řetězec na začátku převedeme na malá písmena. Připravme si proměnné, do kterých budeme ukládat jednotlivé počty. Protože se jedná o složitější kód, nebudeme zapomínat na komentáře.
pozn.: Kdybyste věděli, jak se správně říká nepísmennému znaku,
napište mi to prosím do komentáře pod článek
' řetězec, který chceme analyzovat Dim s As String = "Mount Everest" Console.WriteLine(s) s = s.ToLower() ' inicializace počítadel Dim pocetSamohlasek As Integer = 0 Dim pocetSouhlasek As Integer = 0 ' definice typů znaků Dim samohlasky As String = "aeiouyáéěíóúůý" Dim souhlasky As String = "bcčdďfghjklmnpqrřsštťvwxzž" ' hlavní cyklus For Each c As Char In s Next Console.ReadKey()
Zpočátku si připravíme řetězec a převedeme ho na malá písmena.
Počítadla vynulujeme. Na definice znaků nám postačí obyčejné proměnné
typu String
. Hlavní cyklus nám projede jednotlivé znaky v
řetězci s
, přičemž v každé iteraci cyklu bude v proměnné
c
aktuální znak.
Pojďme plnit počítadla, pro jednoduchost již nebudu opisovat zbytek kódu a přesunu se jen k cyklu:
' hlavní cyklus For Each c As Char In s if samohlasky.Contains(c) Then pocetSamohlasek += 1 Else If souhlasky.Contains(c) Then pocetSouhlasek += 1 End If Next
Metodu Contains()
na řetězci již známe, jako parametr ji lze
předat jak podřetězec, tak přímo znak. Daný znak c
naší
věty tedy nejprve zkusíme vyhledat v řetězci samohlasky
a
případně zvýšit jejich počítadlo. Pokud v samohláskách není,
podíváme se do souhlásek a případně opětovně zvýšíme jejich
počítadlo.
Nyní nám chybí již jen výpis na konec:
{VBNET_CONSOLE}
' řetězec, který chceme analyzovat
Dim s As String = "Mount Everest"
Console.WriteLine(s)
s = s.ToLower()
' inicializace počítadel
Dim pocetSamohlasek As Integer = 0
Dim pocetSouhlasek As Integer = 0
' definice typů znaků
Dim samohlasky As String = "aeiouyáéěíóúůý"
Dim souhlasky As String = "bcčdďfghjklmnpqrřsštťvwxzž"
' hlavní cyklus
For Each c As Char In s
if samohlasky.Contains(c) Then
pocetSamohlasek += 1
Else If souhlasky.Contains(c) Then
pocetSouhlasek += 1
End If
Next
Console.WriteLine("Samohlásek: {0}", pocetSamohlasek)
Console.WriteLine("Souhlásek: {0}", pocetSouhlasek)
Console.WriteLine("Nepísmenných znaků: {0}", s.Length - (pocetSamohlasek + pocetSouhlasek))
Console.ReadKey()
{/VBNET_CONSOLE}
Konzolová aplikace
Mount Everest
Samohlásek: 5
Souhlásek: 7
Nepísmenných znaků: 1
A je to!
ASCII hodnota
Možná jste již někdy slyšeli o ASCII tabulce. Zejména v éře
operačního systému MS DOS prakticky nebyla jiná možnost, jak zaznamenávat
text. Jednotlivé znaky byly uloženy jako čísla typu Byte
, tedy
s rozsahem hodnot od 0
do 255
. V systému byla
uložena tzv. ASCII tabulka, která měla 256 znaků a každému ASCII kódu
(číselnému kódu) přiřazovala jeden znak.
Asi je vám jasné, proč tento způsob nepřetrval dodnes. Do tabulky se
jednoduše nevešly všechny znaky všech národních abeced, nyní se
používá unicode (UTF8) kódování, kde jsou znaky reprezentovány trochu
jiným způsobem. Nicméně ve VB.NET máme stále možnost pracovat s ASCII
hodnotami jednotlivých znaků. Hlavní výhoda je v tom, že znaky jsou
uloženy v tabulce za sebou, podle abecedy. Např. na pozici 97
nalezneme "a"
, 98
"b"
a podobně.
Podobně je to s čísly, diakritické znaky tam budou bohužel jen nějak
rozházeny.
Zkusme si nyní převést znak do jeho ASCII hodnoty a naopak podle ASCII hodnoty daný znak vytvořit:
{VBNET_CONSOLE}
Dim c As Char 'znak
Dim i As Integer 'originální (ASCII) hodnota znaku
'převedeme znak na jeho ASCII hodnotu
c = "a"
i = Asc(c)
Console.WriteLine("Znak {0} jsme převedli na ASCII hodnotu {1}", c, i)
'Převedeme ASCII hodnotu na znak
i = 98
c = Chr(i)
Console.WriteLine("ASCII hodnotu {1} jsme převedli na znak {0}", c, i)
Console.ReadKey()
{/VBNET_CONSOLE}
K převodu znaku na ASCII a naopak používáme funkce Asc()
a
Chr()
. Převodům se říká přetypování, ale o tom se blíže
pobavíme až později.
Cézarova šifra
Vytvoříme si jednoduchý program na šifrování textu. Pokud jste někdy
slyšeli o Cézarově šifře, bude to přesně to, co si zde naprogramujeme.
Šifrování textu spočívá v posouvání znaku v abecedě o určitý, pevně
stanovený počet znaků. Například slovo "ahoj"
se s posunem
textu o 1 přeloží jako "bipk"
. Posun umožníme uživateli
vybrat. Algoritmus zde máme samozřejmě opět vysvětlený a to v článku Cézarova
šifra . Program si dokonce můžete vyzkoušet v praxi - Online cézarova šifra
.
Vraťme se k programování a připravme si kód. Budeme potřebovat
proměnné pro původní text, zašifrovanou zprávu a pro posun. Dále cyklus
projíždějící jednotlivé znaky a výpis zašifrované zprávy. Zprávu si
necháme zapsanou napevno v kódu, abychom ji nemuseli při každém spuštění
programu psát. Po dokončení nahradíme obsah proměnné metodou
Console.ReadLine()
. Šifra nepočítá s diakritikou, mezerami a
interpunkčními znaménky. Diakritiku budeme bojkotovat a budeme
předpokládat, že ji uživatel nebude zadávat. Ideálně bychom poté měli
diakritiku před šifrováním odstranit, stejně tak cokoli kromě písmen.
'inicializace proměnných Dim s As String = "gaiusjuliuscaesar" Console.WriteLine("Původní zpráva: {0}", s) Dim zprava As String = "" Dim posun As Integer = 1 'cyklus projíždějící jednotlivé znaky For Each c As Char In s Next 'výpis Console.WriteLine("Zašifrovaná zpráva: {0}", zprava) Console.ReadKey()
Nyní se přesuneme dovnitř cyklu, převedeme znak c
na ASCII
hodnotu (neboli ordinální hodnotu), tuto hodnotu zvýšíme o
posun
a převedeme zpět na znak. Tento znak nakonec připojíme k
výsledné zprávě:
{VBNET_CONSOLE}
'inicializace proměnných
Dim s As String = "gaiusjuliuscaesar"
Console.WriteLine("Původní zpráva: {0}", s)
Dim zprava As String = ""
Dim posun As Integer = 1
'cyklus projíždějící jednotlivé znaky
For Each c As Char In s
Dim i As Integer = Asc(c)
i += posun
Dim znak As Char = Chr(i)
zprava += znak
Next
'výpis
Console.WriteLine("Zašifrovaná zpráva: {0}", zprava)
Console.ReadKey()
{/VBNET_CONSOLE}
Konzolová aplikace
Původní zpráva: gaiusjuliuscaesar
Zašifrovaná zpráva: hbjvtkvmjvtdbftbs
Program si vyzkoušíme. Výsledek vypadá docela dobře. Zkusme si však
zadat vyšší posun nebo napsat slovo "zebra". Vidíme, že znaky mohou po
"z"
přetéct do ASCII hodnot dalších znaků, v textu tedy již
nemáme jen písmena, ale další ošklivé znaky. Uzavřeme znaky do kruhu tak,
aby posun plynule po "z"
přešel opět k "a"
a dále.
Postačí nám k tomu jednoduchá podmínka, která od nové ASCII hodnoty
odečte celou abecedu tak, abychom začínali opět na "a"
.
Dim i As Integer = Asc(c) i += posun 'kontrola přetečení If i > Asc("z") Then i -= 26 End If Dim znak As Char = Chr(i) zprava &= znak
Pokud i
přesáhne ASCII hodnotu z
, snížíme ho o
26
znaků (tolik znaků má anglická abeceda). Operátor
-=
vykoná to samé, jako bychom napsali i = i - 26
.
Je to jednoduché a náš program je nyní funkční. Všimněme si, že nikde
nepoužíváme přímé kódy znaků, v podmínce je Asc("z")
, i
když bychom tam mohli napsat rovnou 122
. Je to z důvodu, aby byl
náš program plně odstíněn od explicitních ASCII hodnot a bylo lépe
viditelné, jak funguje. Cvičně si zkuste udělat dešifrování.
V následujícím cvičení, Řešené úlohy k 10. lekci VB.NET, si procvičíme nabyté zkušenosti z předchozích lekcí.