Az előző fejezetben részletesen áttekintettük a reguláris kifejezések alapjait. A példákhoz és a hatékony használathoz az előző fejezetben összeszedett tudás táblázatos kivonata talán hasznos lesz:
| Regex minta | jelentése |
|---|---|
\| |
Védőkarakter, mintaillesztés alól spec. karakter kivonása |
. |
Bármelyik karakter |
\w |
Alfanumerikus karakter |
\W |
Nem alfanumerikus karakter |
\d |
Decimális karakter |
\D |
Nem decimális karakter |
\s |
space, tab, enter karakterek |
\S |
Nem space, tab, enter karakterek |
\n |
új sor karakter |
\t |
Tab karakter |
\r |
Kocsi vissza karakter |
[abc] |
a vagy b vagy c karakterekre egyezés |
[^abc] |
a vagy b vagy c karakterekre nem egyezés |
[a-z] |
a-tól z-ig karakterre egyezés |
^a |
Sor elején a betűre egyezés |
Z$ |
Sor végén Z betűre egyezés |
? |
0 vagy 1 alkalommal egyezés |
+ |
1 vagy több alkalommal egyezés |
* |
0 vagy több alkalommal egyezés |
*? |
0 vagy több alkalommal egyezés, lehető legkevesebbszer |
+? |
1 vagy több alkalommal egyezés, lehető legkevesebbszer |
{n} |
N alkalommal egyezés |
{n,m} |
Legalább n, maximum m alkalommal egyezés |
{n,} |
Legalább n alkalommal egyezés |
(asd) |
Részminta definiálása |
(asd\|dsa) |
Vagy az asd vagy a dsa karakterekre illeszkedik |
.NET esetén a reguláris kifejezések megvalósÃtásáért a Regex osztály felel, amit a System.Text.RegularExpressions névtérben találunk meg.
A Regex osztály érdekes konstruktorai:
public Regex (string pattern);
public Regex (string pattern, RegexOptions options);
public Regex (string pattern, RegexOptions options, TimeSpan matchTimeout);
Az egy paraméteres változat esetén a paraméter maga a reguláris kifejezés. A két paraméteres változat esetén a második paraméter beállÃtásokat ad meg a kifejezés számára. A beállÃtások a RegexOptions tÃpusú enum-ban tárolódnak és az alábbi értékeket vehetik fel:
-
RegexOptions.Compiled
Memóriába fordÃtott. Akkor hasznos, ha a mintát sűrűn, vagy sokszor kell illeszteni.
-
RegexOptions.CultureInvariant
Kultúra figyelmen kÃvül hagyása.
-
RegexOptions.IgnoreCase
Kis és nagy betű nem különbözik.
-
RegexOptions.Multiline
Többsoros mód. A $ és a ^ nem soronként értelmezettek, hanem a bemeneti szöveg elejére és végére.
-
RegexOptions.Singleline
Egy soros mód
-
RegexOptions.None
Nincs beállÃtás meghatározva (egy paraméteres konstruktor beállÃtása).
A konstruktor három paraméteres változatában az utolsó paraméter a mintaillesztés maximális idÅ‘korlátját határozza meg. Ez alapértelmezetten végtelenre van állÃtva. Ha a mintaillesztés nem sikerül a meghatározott idÅ‘n belül, akkor egy RegexMatchTimeoutException kivétel keletkezik.
Példaprogram mintaillesztés ellenőrzésre
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace PeldaRegexMatch
{
class Program
{
const string emailPattern = @"[^@]+\@[^\.]+\..+";
static IEnumerable<string> TestCases
{
get
{
yield return "user@test.com";
yield return "test.com";
yield return "user@.com";
yield return "user@1234.com";
yield return "12elemer@server.be";
yield return "valaki@mymail.hu";
}
}
static void Main(string[] args)
{
var expression = new Regex(emailPattern, RegexOptions.Compiled);
foreach (var testcase in TestCases)
{
bool match = expression.IsMatch(testcase);
Console.WriteLine("{0} match status: {1}", testcase, match);
}
Console.ReadKey();
}
}
}
A program kimenete:
user@test.com match status: True
test.com match status: False
user@.com match status: False
user@1234.com match status: True
12elemer@server.be match status: True
valaki@mymail.hu match status: True
A mintaprogram egy egyszerű e-mail cÃm ellenÅ‘rzÅ‘t valósÃt meg. Ennek kapcsán megjegyezném, hogy a fenti Regex minta valószÃnűleg nem fed le minden esetet az RFC szerinti lehetséges mail cÃmekbÅ‘l, Ãgy ne alkalmazzuk éles környezetben.
A kódban a bonyolultságot talán a minta értelmezése jelenti. Nézzük tagonként.
A [^@]+ részlet legalább egy egyezést megkövetel bármilyen karakterből, ami nem a @ karakter. A \@ részlet a kukac karakter szereplését követeli meg. A [^\.]+ minta legalább egy karaktert köt ki, ami nem lehet a . karakter. A \..+ részminta pedig egy pont karakterrel kezdődő részt kér, ami után bármi állhat.
RFC szerinti mail cÃm variálásra az alábbi reguláris kifejezés jobban alkalmas, azonban a példát nem szerettem volna feleslegesen komplexé tenni:
^(?(")(".+?(?<!\\)"@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$
Csere és darabolás minta alapján
A reguláris kifejezések eszköztárában szerepel a sima egyszerű string műveleteknél bemutatott split és replace is.
Csere esetén bármilyen szöveget megadhatunk, amire cserélni szeretnénk, illetve létezik pár speciális csere minta is. Ezek:
${szám}
Az eredeti kifejezésben () jelek között szereplÅ‘ részmintára illeszkedÅ‘ szöveg behelyettesÃtése. A {szám} helyre a részminta sorszámát kell Ãrni. A részminták sorszámozása 0-tól kezdÅ‘dik.
$+
Az eredeti kifejezésben () jelek között szereplÅ‘ utolsó részmintára illeszkedÅ‘ szöveg behelyettesÃtése.
$&
A kifejezésre illeszkedő szövegrészletre cserélés.
$`
A bemeneti szövegből a minta előtt található szövegre cserélés.
$’
A bemeneti szövegből a minta után található szövegre cserélés.
Cserére a reguláris kifejezés példányunk Replace metódusát használhatjuk, ahol az első paraméter a bemeneti szöveg, a második paraméter pedig a csere szöveg. A metódus kimenete pedig a szöveg a cserék végrehajtása után.
string Replace (string input, string replacement);
Darabolásra a Split metódust alkalmazhatjuk szintén a kifejezés példányon. Az egy paraméteres változat csak a bemeneti szöveget várja el. A kétparaméteres változatában a második paraméter a darabolás számát limitálja.
public string[] Split (string input);
public string[] Split (string input, int count);
Reguláris kifejezések és a biztonság
A reguláris kifejezéseket a legtöbb esetben bemenet validációra szoktuk alkalmazni, hogy megnézzük azt, hogy egy adott szöveg megfelel-e egy adott mintának vagy sem1. Ilyen minták kitalálása komplex feladat tud lenni, éppen ezért a leggyakoribb adat mintákról az OWASP projektnek van egy Regex minta gyűjteménye, ami a https://owasp.org/www-community/OWASP_Validation_Regex_Repository cÃmen lelhetÅ‘ fel. Ha ezeket a mintákat alkalmazzuk, akkor nagyon nem tudunk mellélÅ‘ni, ami a biztonságot illeti.
A gondok akkor kezdÅ‘dnek igazán, ha a használt mintánk "gonosz". Gonosznak akkor nevezünk egy reguláris kifejezést, ha a minta illesztés mohóságára épÃt. Ilyen például a (a+)+ minta. Ennek az illesztési ideje exponenciálisan növekszik a bemenet hossza alapján. Ha a szoftverünben egy ilyen minta van, akkor könnyen összeomolhat vagy működésképtelenné válhat a megfelelÅ‘ bemenettÅ‘l.
Éppen ezért az internetről csak olyan kifejezéseket alkalmazzunk, amelyről értjük is, hogy mit csinál, illetve minden esetben lássuk el egy beláthatóan elfogadható (Pl. 3 másodperc) időkorláttal (A Regex 3 paraméteres konstruktorát alkalmazzuk) a mintaillesztést.
-
Ezen alkalmazási terület alapján akár hÃvhatnánk Å‘ket irreguláris kifejezéseknek, hiszen leginkább azt jeleztetjük velük, hogy irregularitás van a megadott mintában.↩