9. diel - Textové reťazce v VB .NET druhýkrát - Práca so znakmi
V predchádzajúcom cvičení, Riešené úlohy k 8. lekcii VB.NET, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.
Ak ste vycítili nejakú podobnosť medzi poľom a textovým reťazcom, tak
ste vycítili správne. Pre ostatné môže byť prekvapením, že
String
je v podstate pole znakov (prvkov typu
Char
) a môžeme s ním aj takto pracovať.
Najprv si v dnešnom Visual Basic .NET tutoriálu vyskúšame, že to všetko funguje. Rozcvičíme sa na jednoduchom vypísanie znaku na danej pozícii:
{VBNET_CONSOLE}
Dim s As String = "VB.NET"
Console.WriteLine(s)
Console.WriteLine(s(1))
Console.ReadKey()
{/VBNET_CONSOLE}
výstup:
Konzolová aplikácia
VB.NET
B
Vidíme, že môžeme ku znakom v reťazci pristupovať cez okrúhlu zátvorku, ako tomu je aj u pole. Sklamaním môže byť, že znaky na danej pozícii sú vo VB.NET read-only, nemôžeme teda napísať:
' Tento kód nefunguje Dim s As String = "VB.NET" s(1) = "C" Console.WriteLine(s) Console.ReadKey()
Samozrejme to ide urobiť inak, neskôr si to ukážeme, zatiaľ sa budeme venovať iba čítanie jednotlivých znakov.
Analýza výskytu znakov vo vete
Napíšme si jednoduchý program, ktorý nám analyzuje zadanú vetu. Bude
nás zaujímať počet samohlások, spoluhlások a počet nepísmenných znakov
(napr. Medzera alebo !
).
Daný textový reťazec si najprv v programe zadáme napevno, aby sme ho
nemuseli pri každom spustení písať. Keď bude program hotový, nahradíme ho
Console.ReadLine()
. Reťazec budeme prechádzať cyklom po jednom
znaku. Rovno tu hovorím, že neapeluje na rýchlosť programu a budeme voliť
názorná a jednoduché riešenia.
Najprv si pripravme kód, definujme si samohlásky a spoluhlásky. Počet nepísmen nemusíme počítať, bude to dĺžka reťazca mínus samohlásky a spoluhlásky. Aby sme nemuseli riešiť veľkosť písmen, celý reťazec na začiatku prevedieme na malé písmená. Pripravme si premenné, do ktorých budeme ukladať jednotlivé počty. Pretože sa jedná o zložitejší kód, nebudeme zabúdať na komentáre.
pozn .: Keby ste vedeli, ako sa správne hovorí nepísmennému znaku, napíšte mi to prosím do komentára pod článok
' reťazec, ktorý chceme analyzovať Dim s As String = "Mount Everest" Console.WriteLine(s) s = s.ToLower() ' inicializácia počítadiel Dim pocetSamohlasek As Integer = 0 Dim pocetSouhlasek As Integer = 0 ' definícia typov znakov 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()
Spočiatku si pripravíme reťazec a prevedieme ho na malé písmená.
Počítadla vynulujeme. Na definícia znakov nám postačí obyčajné premennej
typu String
. Hlavný cyklus nám prejde jednotlivé znaky v
reťazci s
, pričom v každej iterácii cyklu bude v premennej
c
aktuálny znak.
Poďme plniť počítadla, pre jednoduchosť už nebudem opisovať zvyšok kódu a presunu sa len 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
Metódu Contains()
na reťazci už poznáme, ako parameter ju
možno odovzdať ako podreťazec, tak priamo znak. Daný znak c
našej vety teda najprv skúsime vyhľadať v reťazci samohlasky
a
prípadne zvýšiť ich počítadlo. Ak v samohláskach nie je, pozrieme sa do
spoluhlások a prípadne opätovne zvýšime ich počítadlo.
Teraz nám chýba už len výpis na koniec:
{VBNET_CONSOLE}
' reťazec, ktorý chceme analyzovať
Dim s As String = "Mount Everest"
Console.WriteLine(s)
s = s.ToLower()
' inicializácia počítadiel
Dim pocetSamohlasek As Integer = 0
Dim pocetSouhlasek As Integer = 0
' definícia typov znakov
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ások: {0}", pocetSamohlasek)
Console.WriteLine("Spoluhlások: {0}", pocetSouhlasek)
Console.WriteLine("Nepísmenných znakov: {0}", s.Length - (pocetSamohlasek + pocetSouhlasek))
Console.ReadKey()
{/VBNET_CONSOLE}
Konzolová aplikácia
Mount Everest
Samohlások: 5
Spoluhlások: 7
Nepísmenných znakov: 1
A je to!
Ascii hodnota
Možno ste už niekedy počuli o ASCII tabuľke. Najmä v ére operačného
systému MS DOS prakticky nebola iná možnosť, ako zaznamenávať text.
Jednotlivé znaky boli uložené ako čísla typu Byte
, teda s
rozsahom hodnôt od 0
do 255
. V systéme bola
uložená tzv. ASCII tabuľka, ktorá mala 256 znakov a každému ASCII kódu
(číselnému kódu) priradzovala jeden znak.
Asi je vám jasné, prečo tento spôsob nebol platný dodnes. Do tabuľky sa
jednoducho nevošli všetky znaky všetkých národných abecied, teraz sa
používa unicode (UTF8) kódovania, kde sú znaky reprezentované trochu iným
spôsobom. Avšak vo VB.NET máme stále možnosť pracovať s ASCII hodnotami
jednotlivých znakov. Hlavná výhoda je v tom, že znaky sú uložené v
tabuľke za sebou, podľa abecedy. Napr. na pozícii 97
nájdeme
"a"
, 98
"b"
a podobne. Podobne je to s
číslami, diakritické znaky tam budú bohužiaľ len nejako rozhádzané.
Skúsme si teraz previesť znak do jeho ASCII hodnoty a naopak podľa ASCII hodnoty daný znak vytvoriť:
{VBNET_CONSOLE}
Dim c As Char 'znak
Dim i As Integer 'originálny (ASCII) hodnota znaku
'prevedieme znak na jeho ASCII hodnotu
c = "a"
i = Asc(c)
Console.WriteLine("Znak {0} sme previedli na ASCII hodnotu {1}", c, i)
'Prevedieme ASCII hodnotu na znak
i = 98
c = Chr(i)
Console.WriteLine("Ascii hodnotu {1} sme previedli na znak {0}", c, i)
Console.ReadKey()
{/VBNET_CONSOLE}
K prevodu znaku na ASCII a naopak používame funkcie Asc()
a
Chr()
. Prevodom sa hovorí pretypovanie, ale o tom sa bližšie
zabavíme až neskôr.
Cézarova šifra
Vytvoríme si jednoduchý program na šifrovanie textu. Ak ste niekedy
počuli o Cézarově šifre, bude to presne to, čo si tu naprogramujeme.
Šifrovanie textu spočíva v posúvaní znaku v abecede o určitý, pevne
stanovený počet znakov. Napríklad slovo "ahoj"
sa s posunom
textu o 1 preloží ako "bipk"
. Posun umožníme užívateľovi
vybrať. Algoritmus tu máme samozrejme opäť vysvetlený a to v článku Cézarova
šifra. Program si dokonca môžete vyskúšať v praxi - Online cézarova
šifra.
Vráťme sa k programovaniu a pripravme si kód. Budeme potrebovať premenné
pre pôvodné text, zašifrovanú správu a pre posun. Ďalej cyklus
prechádzajúce jednotlivé znaky a výpis zašifrované správy. Správu si
necháme zapísanú napevno v kóde, aby sme ju nemuseli pri každom spustení
programu písať. Po dokončení nahradíme obsah premennej metódou
Console.ReadLine()
. Šifra nepočíta s diakritikou, medzier a
interpunkčných znamienok. Diakritiku budeme bojkotovať a budeme
predpokladať, že ju užívateľ nebude zadávať. Ideálne by sme potom mali
diakritiku pred šifrovaním odstrániť, rovnako tak hocičo okrem písmen.
'inicializácia premenných Dim s As String = "gaiusjuliuscaesar" Console.WriteLine("Pôvodná správa: {0}", s) Dim zprava As String = "" Dim posun As Integer = 1 'cyklus prechádzajúce jednotlivé znaky For Each c As Char In s Next 'výpis Console.WriteLine("Zašifrované správa: {0}", zprava) Console.ReadKey()
Teraz sa presunieme dovnútra cyklu, prevedieme znak c
na ASCII
hodnotu (čiže ordinálna hodnotu), túto hodnotu zvýšime o
posun
a prevedieme späť na znak. Tento znak nakoniec pripojíme k
výslednej správe:
{VBNET_CONSOLE}
'inicializácia premenných
Dim s As String = "gaiusjuliuscaesar"
Console.WriteLine("Pôvodná správa: {0}", s)
Dim zprava As String = ""
Dim posun As Integer = 1
'cyklus prechádzajúce 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é správa: {0}", zprava)
Console.ReadKey()
{/VBNET_CONSOLE}
Konzolová aplikácia
Pôvodná správa: gaiusjuliuscaesar
Zašifrované správa: hbjvtkvmjvtdbftbs
Program si vyskúšame. Výsledok vyzerá celkom dobre. Skúsme si však
zadať vyššiu posun alebo napísať slovo "zebra". Vidíme, že znaky môžu
po "z"
pretiecť do ASCII hodnôt ďalších znakov, v texte teda
už nemáme len písmená, ale ďalšie škaredé znaky. Uzavrieme znaky do
kruhu tak, aby posun plynulo po "z"
prešiel opäť k
"a"
a ďalej. Postačí nám k tomu jednoduchá podmienka, ktorá
od novej ASCII hodnoty odpočíta celú abecedu tak, aby sme začínali opäť
na "a"
.
Dim i As Integer = Asc(c) i += posun 'kontrola pretečeniu If i > Asc("z") Then i -= 26 End If Dim znak As Char = Chr(i) zprava &= znak
Ak i
presiahne ASCII hodnotu z
, znížime ho o
26
znakov (toľko znakov má anglická abeceda). Operátor
-=
vykoná to isté, ako keby sme napísali
i = i - 26
. Je to jednoduché a náš program je teraz funkčná.
Všimnime si, že nikde nepoužívame priame kódy znakov, v podmienke je
Asc("z")
, aj keď by sme tam mohli napísať rovno
122
. Je to z dôvodu, aby bol náš program plne odtienený od
explicitných ASCII hodnôt a bolo lepšie viditeľné, ako funguje. Cvične si
skúste urobiť dešifrovanie.
V nasledujúcom cvičení, Riešené úlohy k 9. lekcii VB.NET, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.