9. díl - Textové řetězce ve VB .NET podruhé - práce s jednotlivými

Ostatní jazyky Visual Basic .NET Základní konstrukce Textové řetězce ve VB .NET podruhé - práce s jednotlivými

V milém dílu seriálu o Visual Basic .NET jsme se naučili pracovat s polem. 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ů (Charů) a můžeme s ním i takto pracovat.

Nejprve si vyzkoušejme, že to všechno funguje. Rozcvičíme se na jednoduchém vypsání znaku na dané pozici:

Dim s As String = "Hello devbook"
Console.WriteLine(s)
Console.WriteLine(s(2))
Console.ReadKey()

Výstup:

Hello devbook
l

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:

Dim s As String = "Hello devbook"
s(1) = "o"
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 = "Programátor se zasekne ve sprše, protože instrukce na šampónu byly: Namydlit, omýt, opakovat."
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é Stringy. 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:

Console.WriteLine("Samohlásek: {0}", pocetSamohlasek)
Console.WriteLine("Souhlásek: {0}", pocetSouhlasek)
Console.WriteLine("Nepísmenných znaků: {0}", s.Length - (pocetSamohlasek + pocetSouhlasek))
Analyzátor samohlásek, souhlásek a znaků ve větě ve Visual Basic .NET

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

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()

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 bojkovat 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 = "cernediryjsoutamkdebuhdelilnulou"
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ě:

Dim i As Integer = Asc(c)
i += posun
Dim znak As Char = Chr(i)
zprava += znak
Cézarova šifra ve Visual Basic .NET

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čne 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í.

Příště si ukážeme, že String umí přecijen ještě něco navíc. Prozradím, že budeme dekódovat Morzeovu abecedu.


 

  Aktivity (4)

Článek pro vás napsal Michal Žůrek (misaz)
Avatar
Autor se věnuje tvorbě aplikací pro počítače, mobilní telefony, mikroprocesory a tvorbě webových stránek a webových aplikací. Nejraději programuje ve Visual Basicu a TypeScript. Ovládá HTML, CSS, JavaScript, TypeScript, C# a Visual Basic.

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


 


Miniatura
Předchozí článek
Cvičení k 8. lekci VB.NET
Miniatura
Následující článek
Cvičení k 9. lekci VB.NET

 

 

Komentáře

Avatar
Pavel Růžička:

Ahoj,
Myslím , že v řádku u if-then je chyba. neměl by být zápis "pocetSamohlasek = + 1" ?

 
Odpovědět 17. ledna 13:26
Avatar
Odpovídá na Pavel Růžička
Michal Žůrek (misaz):

ne

pocetSamohlasek += 1

je správně. Operátor přičítání k proměnné je +=. Dá se to alternativně (a delší cestou) zapsat jako

pocetSamohlasek = pocetSamohlasek + 1
Odpovědět  +1 17. ledna 13:29
Nesnáším {}, proto se jim vyhýbám.
Avatar
Pavel Růžička:

Omlouvám se, už jsem to dočetl. :-)

 
Odpovědět  +1 17. ledna 13:33
Avatar
Pavel Růžička:

Přeci jen ještě jeden dotaz.

int i = (int)c;
i += posun;
char znak = (char)i;
zprava += znak;

To mi přijde jako z C místo VB. Uvést k životu se mi to podařilo po úpravě:

Dim i As Integer = Asc(b)
            i += posun
            Dim znak As Char = Chr(i)
            zprava += znak
 
Odpovědět  +1 17. ledna 19:06
Avatar
Odpovídá na Michal Žůrek (misaz)
Libor Šimo (libcosenior):

V článku si nalísal:
"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:

Dim s As String = "Hello devbook"
s(1) = "o"
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ů."

Nenašiel aom ako sa to robí a potrebujem zmeniť napríklad prvý znak reťazca s(0).
Poradíš?

Odpovědět 10. února 9:44
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovědět 10. února 10:22
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
Odpovídá na Michal Štěpánek
Libor Šimo (libcosenior):

Je tam toho dosť, určite by som nejaký kód napísal, ale asi by nebol optimálny.
V céčku by som na to použil cyklus a vytvoril by som nový reťazec s veľkým prvým písmenom. Asi by to podobne išlo aj vo VS.
Ako by si napísal kód, ktorý zmení prvý znak reťazca z malého písmena na veľké? Je zaručené, že prvý znak je malé písmeno.

Odpovědět 10. února 13:32
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na Libor Šimo (libcosenior)
Michal Žůrek (misaz):

substringem si vezmeš první písmeno, uděláš s ním co chceš a to spojíš se zbytkem, který taky získáš substringem.

Odpovědět 10. února 16:19
Nesnáším {}, proto se jim vyhýbám.
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 8 zpráv z 8.