Regulární výrazy
Nebudu se zde pouštět do rozsáhlých definic regulárních výrazů, ale pouze poukážu na případy, kdy je dobré regulární výrazy využít. Představte si, že máte aplikaci která přijímá od uživatele údaje jako např. PSČ, email, věk, datum (neberme v potaz existující komponenty - ComboBox, DropDownList, MonthCalendar neno NumericUpDown) a chcete zamezit vložení nekorektních informací. Případně máme HTML stránku z obrázky a chceme získat adresy jednotlivých obrázků. Na tyto a mnohé další věci se právě hodí využití regulárních výrazů.
Než se vrhneme na psaní jednoduchých aplikací, podíváme se na jednotlivé znaky používané v regulárních výrazech
- ^ - pokud použijeme regulární výraz '^a' říkáme tím, že slovo musí začínat na znak 'a'
- $ - opak předchozího, slovo musí končit na znak uvedený před $
- . - jakýkoliv znak kromě znaku nového řádku '\n'
- a | b - a nebo b. Např. "[t|b]all" - výsledek bude buď tall nebo ball
- + - znak před '+' se může opakovat 1x nebo vícekrát
- * - znak před '*' se může opakovat 0x nebo vícekrát
- ? - znak před '?' se může opakovat 0x nebo 1x
- [ a - z ] - znaky v rozmezí od 'a' do 'z'
- { n, m} - výskyt znaku od n do m. Např. "aho{1,2}j" - výsledek ahoj, ahooj
- { n } - počet opakování znaku
- { n, } - počet opakování znaku od n do 'nekonečna'
- \t - tab
- \n - new line
- \e - escape
- \r - carriage return
- \v - vertical tab
- \f - form feed
- \a - bell (alarm)
- \d - číslo
- \D - NEčíslo
- \s - bílé znaky. Ekvivalentní zápis [\f\n\r\t\v]
- \S - nebílé znaky
- \w - slova obsahující znaky a-z, A-Z, 0-9 a _
- \W - slova neobsahující výše uvedené znaky
Nyní se podíváme na pár příkladů. Začneme např. u zmiňovaného věku. Vytvoříme si tedy consolovou aplikaci, která přečte uživatelem zadaný vstup a rozhodne, zda-li zadal věk ve správném formátu či nikoliv
using System;
using System.Text.RegularExpressions;
namespace Clanek
{
class Program
{
static void Main(string[] args)
{
string vek = Console.ReadLine();
// vek muze obsahova 1 nebo 2 cislice.
// omlouvam se, ale 100-lete osoby neberu v potaz
string vzor = @"^\d{1,2}$";
// vytvorim objekt Regex (namespace: System.Text.RegularExpressions)
// a jako parametr predam muj vzor pro vek
Regex r = new Regex(vzor);
// zavolam metodu IsMatch s parametrem vek
// a vysledekem bude hodnota true nebo false
Console.WriteLine(r.IsMatch(vek));
Console.ReadLine();
}
}
}
|
Regulární výraz pro validaci např. PSČ u nás by vypadal takhle
static void Main(string[] args)
{
string psc = Console.ReadLine();
// psc u nas obsahuje 5 cislic, vzor bude
// tedy velice jednoduchy
string vzor = @"^\d{5}$";
Regex regex = new Regex(vzor);
Console.WriteLine(regex.IsMatch(psc));
Console.ReadLine();
}
|
V dalším ukázkovém příkladu se podíváme jak využít regulární výrazy pro ošetření správného zadání datumu
static void Main(string[] args)
{
// datum se muze zadat ve tvaru 02.02.2008, ale i 2.2.2008
string datum = Console.ReadLine();
/* vzor se tedy sklada z
* jednoho nebo dvou cisel
* tecky
* jednoho nebo dvou cisel
* tecky
* cislo 19 plus libovolne dve cislice nebo cislo 200 plus cislo od 0 do 8
*/
string vzor = @"^\d{1,2}\.\d{1,2}\.(19\d{2}|200[0-8])$";
Regex regex = new Regex(vzor);
// pokud uzivatel zda datum spavne musime jeste zkontrolovat
// jestli se jedna o validni datum, tedy aby nezadal napr. 30.2.
if (regex.IsMatch(datum))
{
if (ZkontrolujDatum(datum))
Console.WriteLine("Datum v poradku");
}
else
Console.WriteLine("Datum ma spatny format");
Console.ReadLine();
}
private static bool ZkontrolujDatum(string datum)
{
string[] pomDatum = datum.Split('.');
int den = Convert.ToInt32(pomDatum[0]);
int mesic = Convert.ToInt32(pomDatum[1]);
int rok = Convert.ToInt32(pomDatum[2]);
bool spravneDatum = false;
switch (mesic)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
if (den > 31)
Console.WriteLine("Mesic {0} ma 31 dni,"
+"vy jste zadal {2} !!!",mesic, den);
else
spravneDatum = true;
break;
case 4:
case 6:
case 9:
case 11:
if (den > 31)
Console.WriteLine("Mesic {0} ma 31 dni,"
+"vy jste zadal {2} !!!",mesic, den);
else
spravneDatum = true;
break;
case 2:
bool prestupny;
prestupny = JePrestupny(rok);
if (prestupny)
{
if (den > 29)
Console.WriteLine("Mesic {0} ma v roce {1}"
+ "29 dni, vy jste zadal {2} !!!",mesic, rok, den);
else
spravneDatum = true;
}
else
{
if (den > 28)
Console.WriteLine("Mesic {0} ma v roce "
+"{1} 28 dni, vy jste zadal {2} !!!",
mesic, rok, den);
else
spravneDatum = true;
}
break;
default:
Console.WriteLine("Mesic {0} neexistuje !!!", mesic);
break;
}
return spravneDatum;
}
private static bool JePrestupny(int rok)
{
return ((rok % 4 == 0) && (rok % 100 != 0) || (rok % 400 == 0));
}
|
Až doposud jsme využívali regulární výrazy pro validaci vstupních informací, ale tentokráte se podíváme jak získat ze vstupu konkrétní data. Uvážíme-li opět příklad s datumem kde budeme chtít nyní pomocí regulárních výrazu získat hodnotu roku. Kód bude vypadat takto:
static void Main(string[] args)
{
string datum = "12.13.2008";
/* regularni vyraz zjednodusime a bude ve formatu
* dve cisla
* tecka
* dve cisla
* tecka
* ctyri cisla
*/
// pro ziskani roku vyuzijeme tzv. skupinum, kde si posledni ctyri cisla
// pojmenujeme jako rok. Oznaceni se znaci bud ?<rok> nebo ?'rok'
Regex regex = new Regex(@"^(\d{1,2})\.(\d{1,2})\.(?<rok>\d{4})$");
// zavolame metodu Match, ktera nam dany vstup rozdeli na skupiny
// ale my chceme pouze specifickou cast proto zavolame metodu Result
// s parametrem ${rok}, ktera nam vrati rok, tedy to co chceme
int rok = Convert.ToInt32(regex.Match(datum).Result("${rok}"));
Console.WriteLine(rok.ToString());
Console.ReadLine();
}
|
V poslední ukázce využití regulárních výrazů se podíváme jak převést datum z formátu dd.mm.rrrr na rrrr/mm/dd:
static void Main(string[] args)
{
string datum = "12.13.2008";
/* regularni vyraz zjednodusime a bude ve formatu
* dve cisla
* tecka
* dve cisla
* tecka
* ctyri cisla
*/
string vzor = @"^(?<den>\d{1,2})\.(?<mesic>\d{1,2})\.(?<rok>\d{4})$";
// muj novy format datumu rrrr/mm/dd
string novyFormat = "${rok}/${mesic}/${den}";
// zavolam statickou metodu Replace a jako parametry predam vstupni datum,
// vzor a vysledny novy format
Console.WriteLine(Regex.Replace(datum, vzor, novyFormat));
Console.ReadLine();
}
|