V minulém dílu jsem slíbil, že se budeme věnovat práci s textem a textovými řetězci. Nejprve si ukážeme nejpoužívanější vlastnosti a metody datového typu String. Pro hodnotu typu String budu používat termín text či řetězec, pro část této hodnoty budu používat termín podřetězec či sekvence znaků.
Zjištění délky řetězce
Každý řetězec má vlastnost Length, která vrátí jeho délku, čili celkový počet znaků.
Dim txt As String = "Červená Karkulka potkala vlka."
MsgBox(txt.Length)
Práce s jednotlivými znaky
Pokud potřebujeme získat například šesté písmeno z textu, použijeme vlastnost Chars, což je pole znaků. Znaky se vždycky číslují od nuly, i ve všech dalších ukázkách.
Dim txt4 As String = "abcdefgh!"
MsgBox(txt4(0))
MsgBox(txt4(3))
MsgBox(txt4(8))
Vypsání podřetězce z textu
K získání části textu máme metodu Substring. Můžeme jí předat buď dva parametry - číslo prvního znaku (začíná se od nuly) a délku požadované části textu, čímž získáme část ze začátku či z prostředka řetězce, anebo jeden jediný parametr - číslo prvního znaku (opět od nuly), což vrátí podřetězec od daného znaku až do konce. Lépe je to vidět na ukázce:
Dim txt5 As String = "Kočka přede."
MsgBox(txt5.Substring(2, 6))
MsgBox(txt5.Substring(6))
Zjištění výskytu podřetězce
Metoda Contains umožňuje zjistit, jestli daný text obsahuje určitou sekvenci znaků. Pokud ano, vrátí True, jinak False. Použití je velmi jednoduché:
Dim txt2 As String = "Červená Karkulka potkala vlka."
MsgBox(txt2.Contains("kulka"))
MsgBox(txt2.Contains("Kulka"))
Kontrola začátku a konce řetězce
Občas potřebujeme ověřit, zda text začíná či končí nějakým podřetězcem. K tomu nám slouží metody StartsWith, resp. EndsWith. Vrací samozřejmě hodnoty True a False.
Dim txt3 As String = "*104*#"
MsgBox(txt3.StartsWith("*1"))
MsgBox(txt3.EndsWith("*1"))
MsgBox(txt3.EndsWith("*#"))
Nalezení prvního a posledního výskytu podřetězce
Metoda Contains nám vrátila, jestli text daný podřetězec obsahuje. Ale nevrátila nám jeho pozici, abychom s ním mohli dále pracovat. K tomu máme metody IndexOf a LastIndexOf. Obě vrátí pořadí prvního znaku hledané sekvence (čísluje se opět od nuly). Jak ale samotné hledání funguje? Metoda IndexOf prohledává text od začátku, metoda LastIndexOf od konce. Jakmile najdou daný podřetězec, vrátí pozici prvního znaku tohoto podřetězce. Pokud by text daný podřetězec neobsahoval, metody vrátí hodnotu -1, což musíme vzít v úvahu.
Dim text As String = "aBBaBBaa"
MsgBox(text.IndexOf("BBa"))
MsgBox(text.LastIndexOf("BBa"))
MsgBox(text.IndexOf("c"))
Nahrazování podřetězců v textu
Často musíme nahradit určité sekvence znaků v textu sekvencí jinou, k tomu máme metodu Replace. Předáme jí to, co chceme nahradit, a to, čím to chceme nahradit, a dostaneme výsledek.
Dim nahradit As String = "Veverka kopla do bagru. Veverka vylezla na strom."
MsgBox(nahradit.Replace("Veverka", "Liška"))
Rozdělení více hodnot do pole a jejich opětovné spojení
Tuto poměrně složitou funkci má v sobě datový typ String zabudovanou. Často potřebujeme zpracovat (často užíváme termín parsovat) třeba čísla oddělená čárkami. A právě k tomuto účelu máme metodu Split. Předáme jí oddělovač, tedy znak nebo sekvenci znaků, kterými jsou jednotlivé hodnoty odděleny, a dostaneme pole stringů, které pak můžeme třeba projít cyklem.
Pokud chceme pole stringů spojit, použijeme metodu Join, předáme jí oddělovač a pole, které spojujeme, a dostaneme hodnotu typu String. Všimněte si, že všechny metody a vlastnosti jsme volali stylem <proměnná>.<metoda>, ale najednou voláme String.Join. Důvod je prostý - pole, které chceme spojit, není typu String, a samotné pole žádnou metodu Join nemá, protože tato metoda je specifická pro typ String. Metoda Join je tzv. statická metoda, což znamená, že ji nemůžeme volat přes instanci objektu (proměnnou), ale přes datový typ (String). Důvodem je to, že tato metoda nepracuje s již vytvořeným Stringem, ale vytváří nový. Podobných metod existuje hodně, již jsme se jistě setkali s metodou TryParse datového typu Integer, která bezpečně převáděla text na číslo.
Dim hodnoty As String = "-1,13,17,222,0.15,19"
Dim vysl() As String = hodnoty.Split(",")
For i As Integer = 0 To vysl.Length - 1
MsgBox(vysl(i))
Next
MsgBox(String.Join(";", vysl))
Oříznutí "bílých" znaků ze začátku a konce textu
Někdy se nám stává, že text začíná tabulátorem, koncem řádku nebo mezerou, což se nám tak úplně nehodí do krámu. Ještě že máme metodu Trim, která se těchto potvůrek zbaví:
Dim oriznout As String = " slovo "
MsgBox(oriznout.Trim())
Víceřádkový String
Pokud vypisujeme na obrazovku třeba MessageBox, je často vhodné pro lepší čitelnost rozdělit dlouhou větu do více řádků. Pokud trochu znáte starší verze jazyka Visual Basic, používala se konstanta vbCrLf. Tu můžeme využít i ve Visual Basic .NET, ale spíš bych se klonil k použití Environment.NewLine, protože na každém operačním systému vypadá konec řádku trošku jinak. Na Windows to jsou znaky (13 - CR a 10 - LF), na Linuxu jen znak 13 - CR a na Mac OS zase jen znak 10 - LF. Dnes sice ještě .NET aplikace nejsou plně podporovány jinde než na Windows, ale stejně je lepší s touto možností počítat, i když je to pro nás trochu více psaní.
Dim dvaRadky As String = "První řádek." & Environment.NewLine & "Druhý řádek."
Velká a malá písmena
Poslední dvě metody datového typu String, které si ukážeme, umí převádět text na velká a malá písmena. Jsou to metody ToUpper pro velká písmena a ToLower pro malá písmena. Jejich použití je velice snadné:
Dim jmeno As String = "KleOFác"
MsgBox(jmeno.ToLower())
MsgBox(jmeno.ToUpper())
Jak na dlouhé texty a jejich skládání
V určitých situacích potřebujeme pracovat s poměrně dlouhým textem. Pokud použijeme standardní operátor &, může se stát, že aplikace bude pomalá. Pokud tedy skládáme za sebe dlouhé texty, je výhodné použít objekt StringBuilder, který je mnohonásobně rychlejší.
Vytvoříme tedy nový objekt typu StringBuilder a text přidáváme na konec metodou Append či AppendLine. Append jen připíše předaný text na konec dosavadního textu, AppendLine za přidaný text automaticky vloží konec řádku. Hotový text získáme zavoláním metody ToString.
Dim sb As New System.Text.StringBuilder()
For i As Integer = 1 To 500
sb.Append("Číslo ")
sb.Append(i)
sb.AppendLine(".")
Next
MsgBox(sb.ToString())
To je pro tento díl vše. Jsem rád, že se vám seriál líbí, jak je vidět z diskusí pod články, pokud máte jakékoliv náměty na témata, kterým by se měl věnovat, určitě napište do diskuse nebo na e-mail.
Update: Doporučuji přečíst diskusi pod článkem, je v ní něco o regulárních výrazech pro složitější vyhledávání. V dohledné době o tom snad napíši další článek pro pokročilejší.
Minisoutěž - zadání
Dobrý programátor musí umět přemýšlet, zkuste tedy potrápit myšlení a vyřešit následující úkoly:
- Napište funkci, které předáte křestní jméno a funkce jej vrátí správně zapsané, tzn. první písmeno velké a ostatní malá. Pokud jí tedy předáte KLeofÁcek, musí vrátit Kleofácek.
- Napište funkci, které předáte cestu k nějakému souboru, a ona vám z ní vytáhne pouze název souboru s příponou. Takže pokud jí dáte C:\Složka\Podsložka\soubor.txt, vrátí soubor.txt.
- Napište funkci, které předáte text a ona vám jej vrátí pozpátku. Pokud jí tedy předáte Včera večer, vrátí rečev arečV.
Minisoutěž - správná řešení a připomínky
1. Jednoduchá úloha na metody Substring, ToUpper a ToLower. Připomínám, že metoda Substring má dvě možnosti použití - buď dva parametry (první znak, délka podřetězce), nebo jeden parametr (první znak). Zde se právě hodilo použít i volání s jedním parametrem, která vrátí podřetězec od prvního znaku až do konce (není nutné tedy dávat druhý parametr a kvůli tomu počítat délku řetězce a odečítat od ní jedničku, jak mnozí z vás dělali, je to sice správně, ale víc práce). Mnoho z vás také používalo StringBuilder, což není špatně, ale v tomto případě je to kanón na vrabce - slučování řetězců je jen jedno a rychlostní rozdíl bude naprosto zanedbatelný. Nejjednodušší řešení bude vypadat takto:
Function Jmeno(ByVal jm As String)
Return jm.Substring(0, 1).ToUpper() & jm.SubString(1).ToLower()
End Function
2. Tato úloha měla procvičit metody Substring a LastIndexOf. Pomocí LastIndexOf si v řetězci najdeme poslední zpětné lomítko, přičteme k výsledku 1 (aby lomítko nebylo zahrnuto do výsledku, a pokud tam náhodou není a LastIndexOf vrátí -1, stane se z ní nula, čímž se vybere celý řetězec, což je také správně), a pak pouze použijeme Substring. Opt stačí předat metodě Substring pouze pozici, od které chceme text odříznout, nemusíme počítat, kolik znaků zbývá do konce řetězce. Jinak podotýkám, že pro tento účel lze použít funkci System.IO.Path.GetFileName(soubor).
Function Soubor(ByVal fn As String)
Return fn.Substring(fn.LastIndexOf("\") + 1)
End Function
3. Tato funkce je o trochu složitější a asi se vyplatí použít StringBuilder, spojování řetězců bude víc. Je vhodné použít klesající For cyklus, ale jde to samozřejmě i cyklem normálním a správné pozice znaků počítat.
Function Pozpatku(ByVal s As String)
Dim sb As New StringBuilder()
For i As Integer = s.Length - 1 To 0 Step -1 'cyklus jde pozpátku (díky Step -1)
sb.Append(s(i))
Next
Return sb.ToString()
End Function
Musím říci, že jsem byl překvapen počtem řešení, která mi dorazila hned během prvního dne. Rád bych poděkoval všem soutěžícím za účast.
Minisoutěž - výsledky
Došlo mi celkem 8 řešení, všechna byla správná, nejrychleji to ovšem stihnul pan Vratislav Renner, kterému posílám slibované DVD Get Ready 2 s přednáškami a materiály o .NET frameworku.