Strona początkowa

Wyrażenia regularne

Wyrażenia regularne stanowią doskonały sposób na badanie i modyfikowanie tekstu. Dzięki swej olbrzymiej elastyczności pozwalają w łatwy sposób pobierać pasujące fragmenty tekstu. To tyle książkowej teorii. A czym są wzorce w praktyce? Powiedzmy, że mamy kod pocztowy. Kod taki można opisać w następujący sposób: na początku są 2 dowolne cyfry, potem znak myślnika, po czym występują trzy dowolne cyfry (np. 02-380). Powyższy opis kodu pocztowego to właśnie wzorzec. Powiedzmy, że w jakimś tekście chcielibyśmy znaleźć takie kody pocztowe. Problem w tym, że nie wiemy jakie one mają numery... I tutaj właśnie pomogą nam wzorce.

Przykładowy wzorzec może mieć np postać /^[a-zA-Z]{2,}\s[a-zA-Z]{2,}$/. Może się on wydawać bardzo skomplikowanym zapisem, jednak w praktyce tak nie jest!

Aby w Javascript korzystać z wyrażeń regularnych, musimy utworzyć obiekt RegExp(wyrażenie,flaga), który przyjmuje 2 argumenty: wyrażenie, którym będziemy testować, oraz dodatkowe flagi, które poznamy w tym rozdziale.

	var Wyrazenie = new RegExp("prawdzamy//?*" , "g")
    
    lub 
    
    var Wyrazenie = /sprawdzamy/?*/g
    

Którą metodę wybrać?
Każda z nich ma swoje wady i zalety. Pierwsza wymaga poprzedzania specjalnych znaków np ? (które zaraz poznamy) podwójnym ukośnikiem //. W drugiej metodzie specjalne znaki poprzedzamy jednym ukośnikiem, ale całe wyrażenie musimy objąć parą ukośników. Większość deweloperów wybiera drugą metodę, jest to jednak kwestia gustu.

Metaznaki

Każdy wzorzec składa się z meta znaków, czyli specjalnych znaków, które opisują jak mają wyglądać wyszukiwane fragmenty tekstu. Przykładowo wzorzec składający się z meta znaków p.p. będzie pasował do słowa "popo", ale równie dobrze będzie pasował do słowa "papi". Poniżej zamieściłem tabelę zawierającą opis meta znaków.

MetaznakZnaczeniePrzykład wyrażeniaZgodne ciągi z wyrażeniemNiezgodne ciągi z wyrażeniem
^początek wzorca^zazapałka, zadra, zapłon, zarazekkazanie, poza, bazar
$koniec wzorcaaz$
^.arka$
uraz, pokaz
barka, warka
azymut, pokazy
parkan
.dowolny pojedyńczy znak.an.apanda, Wanda, panna, kaniarana, konia
[...]dowolny z wymienionych znaków; możemy podawać kolejne znaki lub wpisywać zakre - na przykład [a-z] oznacza wszystkie małe litery. Wymieniając specjale znaki z końca tej tabeli nie musimy poprzedzać znakiem \[a-z]an[nd]a
[a-z][a-zA-Z0-9.-][pus]
pana, panda, wanna
pas, mAs, p2p, m3u, b-s, z.u
Wanda, kania
Bas, bal, balu, mp3
[^...]dowolny z niewymienionych znakówkre[^st]krew, kremkres, kret
|dowlony z rozdzielonych znakiem ciągów[nz]a|pod|przed
trzynasty|13-ty|13
na, za, pod, przed
trzynasty, 13-ty, 13
 
(...)zawężenie zasięgug(ż|rz)eg(ż|rz)(u|ó)łka
(ósmy|8-my|8)(maj|maja)
gżegżółka, gżegrzółka, gżegrzułka, grzegrzułka
ósmy maja, 8-my maj, 8 maja
 
?zero lub jeden poprzedzający znak lub element; elementem może być na przykład wyrażenie umieszczone wewnątrz nawiasów (...)ro?uter
(ósmy|8(-my)?)maja?
router, ruter
ósmy maja, ósmy maj, 8-mymaja, 8-my maj, 8 maja, 8 maj
 
+jeden lub więcej poprzedzającch znaków lub elementóe; elementem może być na przykład wyrażenie umieszczone wewnątrz nawiasów (...)[0-9]+[abc]
pan+a
(tam)+
10a, 1b, 003c, 42334b
pana, panna, pannnna
tam, tamtam, tamtamtam
a, b, c, z, 14, 03, 12d, 1231z
paa, panda, ta, tamta, mat
*zero lub więcej poprzedzającch znaków lub elementóe; elementem może być na przykład wyrażenie umieszczone wewnątrz nawiasów (...)[0-9]*[abc]
pora*n*a*
10a, 1b, 003c, 42334b, a, b, c
por, poa, poranna, poraannnaa, pornnna
k, 2335, porada, panna
{4}dokładnie 4 porzedzające znaki lub elementy[0-9]{4}8765, 8273, 263512345, 234, 2123456
{4,}4 lub więcej poprzedzających znaków lub elementów[ah]{4,}haha, haaaaahaha, ahaaahaa, ha, hehe, aha
{2,4}od 2 do 4 poprzedzających znaków lub elementówp.{2,4}apiana, pola, polanapsa, poranna
\.znak kropki[0-9]{,3}\.[0-9]{,3}\.[0-9]{,3}128.0.0.2128-0-0-2
\*znak *\*.+*nicnic*, nic
\/znak /^\/\/$// 
\?znak ?^.+\?$Czy to jest kot?Czy to jest kot
\:znak :^.+\:$Oto one::nic
\.znak .\.+...... 
\^znak ^.*\^To jest ^To jest &
\+znak +[0-9]+\+[0-9]+928374+2983223873-32787
238738278
\\znak \c\:\\c:\ 
\=znak =[0-9]+\+[0-9]+\=[0-9]+11+12=2311+12+23
\|znak |x \|\| yx || y 

Flagi

Poza wymienionymi metaznakami istnieją specjalne parametry (flagi), które oddziałują na wyszukiwanie wzorców.:

	var Wyrazenie = /[a-z]*/mg
	var Wyrazenie = new RegExp("[a-z]*","g")
	
znak Flagiznaczenie
ipowoduje niebranie pod uwagę wielkości liter
gpowoduje zwracanie wszystkich psujących fragmentów, a nie tylko pierwszego
mpowoduje wyszukiwanie w tekście kilku linijkowym. W trybie tym znak początku i końca wzorca (^$) jest wstawiany przed i po znaku nowej linni (\n).
spowoduje włączenie przeszukiwania jedno linijkowego. W trybie tym znak . oznacza nową linijkę

Klasy znaków

Dodatkowo Javascript udostępnia specjalne klasy znaków. Zamiast wyszukiwać wszystkich liter za pomocą [a-zA-Z_] możemy skorzystać z klasy znaków \w.

Klasa znakówznaczenie
\sznak spacji, tabulacji lub nowego wiersza
\Sznak nie będący spacją, tabulacją lub znakiem nowego wiersza
\wkażdy znak będący literą, cyfrą i znakiem _
\Wkażdy znak nie będący literą, cyfrą i znakiem _
\dkażdy znak będący cyfrą
\Dkażdy znak nie będący cyfrą

Zastosowanie metody test()

Zacznijmy od najprostszych rzeczy czyli od sprawdzenia, czy w danym tekście występuje nasz wzorzec:

Metoda test() służy do sprawdzania, czy dane wyrażenie znajduje się w tekście:

    var tekst = "cat dog";
	var wzor = /cat/;
	wzor.test(tekst) === true //bo cat znajduje się w tekście
    
   	var wzor2 = /^cat$/;
	alert(wzor.test(tekst)); //false - bo wzorzec zaczyna się z początkiem i kończy z końcem tekstu (znaki ^ i $) - jedyny pasujący tekst to "cat"
    
  	var tekst = "Turlal goryl po Urlach kolorowe korale...";
	var wyrazenie = new RegExp("[A-Z]{1}[^\s]+");
	wyrazenie.test(tekst) === true //bo w tekście jest wyraz zaczynający się z dużej litery, po którym następują małe litery (np. Turlal)
	

[A-Z]{1} - jedna duża litera
[^\s]+ - plus oznacza jeden lub więcej znaków, a [^\s] oznacza znak nie będący spacją - czyli razem: jeden lub więcej znaków nie będących spacją

  	var tekst = "Turlal goryl po Urlach kolorowe korale...";
	var wyrazenie = new RegExp("[0-9]+");
	wyrazenie.test(tekst) === false //bo w tekście nie ma żadnej cyfry

	var wyrazenie = new RegExp("[0-9]*");
	wyrazenie.test(tekst) === true //w tekście nie ma żadnej cyfry, ale * oznacza 0 lub więcej
	

Zastosowanie metody exec()

W powyższych przykładach sprawdzaliśmy tylko czy dany ciąg w ogóle występuje w danym tekście. Aby uzyskać dostęp do pasujących fragmentów, skorzystamy z metody exec() wraz z flagą "g":

	var tekst = "Fantomas robi mase - marchewkowo-marcepanowa";
	var wyrazenie = new RegExp("mas", "g"); //stosujemy flagę g, by sprawdzić wszystkie wystąpienia
	var tablicaWynikow = wyrazenie.exec(tekst);	
    if (tablicaWynikow.length) {
    	console.log(tablicaWynikow.join('-'));
    }
    

Obiekt String posiada metodę match(), która spełnia tę samą funkcję co metoda exec() obiektu RexExp. Możemy więc napisać powyższy skrypt nieco inaczej:

	var tekst = "Fantomas robi mase - marchewkowo-marcepanowa";
	var wzor = /mas/g;
	var tablicaWynikow = tekst.match(wzor);	
    if (tablicaWynikow.length) {
    	console.log(tablicaWynikow.join('-'));
    }
    

W kolejnym przykładzie korzystamy z klasy znaków czyli [...], w których podajemy grupę znaków, z których będzie wybierany pasujący znak:

    var tekst = "kot, pot, Wot Lot";
	var wzor = /[kpw]ot/gi;
	var znalezione = tekst.match(wzor); //kot, pot, Wot
    
    var tekst = "Numer1, Numer2, Numer3, NumerB, Numer5, NumerD";
	var wzor = /Numer[1-4A-C]/g;
	var znalezione = tekst.match(wzor); //Numer1, Numer2, Numer3, NumerB
    

Zastosowanie metody search()

Metoda search() obiektu RexExp działa tak samo jak metoda indexOf() obiektu string, czyli zwraca indeks pierwszego wystąpienia podciągu w ciągu:

    var tekst = "Fantomas robi mase - marchewkowo-marcepanowa";
    var wzor = /at/gi";
    console.log("Search: " + tekst.search(wzor));
    console.log("Index of: " + tekst.indexOf("at"));    
    

Zastosowanie metody replace()

Obiekt string posiada metodę replace(), która służy do zamiany jednego ciągu na drugi. Przy jej stosowaniu możemy używać wyrażeń regularnych:

	var tekst = "Kolorowy kolor nie jest kolorowy?...";
	document.write(tekst + "<br />");
	var wzor = /lor/g //Nasze wyrazenie
	document.write(tekst.replace(wzor,"<strong>ral</strong>")); //Wyszukujemy w tekście wszystkie wystapienia "lor" i zamieniamy je na pogrubione "ral"
	

Jako drugi argument tej metody możemy podać funkcję. Pobiera ona jeden argument - znaleziony fragment tekstu, oraz zwraca tekst, który zastąpi znaleziony fragment:

    var tekst = "Super Samson jest fajny.";
	var wzor = /fajny/;
	var zamieniony = tekst.replace(wzor, function(match) {
		return "super" + match;
	});
	console.log(zamieniony); //Super Samson jest super fajny
	

Czy liczba

Chcemy sprawdzić, czy użytkownik wpisał numer. Jak widać w tabeli zamieszczonej powyżej, Javascript udostępnia nam klasę \d, która oznacza dowolą cyfrę:

	var zmienna = "909384758699";
	var wzor = /^\d+$/
	if (wzor.test(zmienna)) {
		document.write("To jest liczba")
	} else {
		document.write("To nie jest liczba...")
	}
	

Sprawdzanie Kodu Pocztowego

Aby wyszukać w tekście kod pocztowy uzyjemy wyrazenia:

	var WzorKoduP = /[0-9]{2}-[0-9]{3}/g;
	//lub
	var WzorKoduP = /[\d]{2}-[\d]{3}/g;
	

[0-9]{2} - powinny znaleźć się 2 cyfry
- - po 2 cyfrach powinien znaleźć się znak -
[0-9]{3} - po kturym powinny znaleźć się 3 cyfry
g - mają być zwrócone wszystkie wyszukane pasujące ciągi

Nasz wzór możemy wykorzystać w skrypcie za pomocą metody match (zwracającej pasujące ciągi):

	var tekst = "Moj kod pocztowy to nie 12-323 ani tez 03-400 ... jest po prostu inny.";
	var WzorKoduP = /[0-9]{2}-[0-9]{3}/g; //parametr g nakazuje zwrócenie wszystkich znalezionych ciągów (normalnie zwracany jest tylko pierwszy)
	var a = tekst.match(WzorKoduP);
	if (a) {//jeżeli w a znajdują się pasujące ciągi
		for (x=0; x<a.length; x++) {
			document.write(a[x]+"<br />");
		}
	}
	

Weryfikacja Imienia i Nazwiska

Wzorzec opisujący poprawność tych danych ma postać:

	var WzorNazwiska = /^[a-zA-Z]{2,}\s+[a-zA-Z]{2,}$/;
	//lub
	var WzorNazwiska = /^[\D]{2,}\s+[\D]{2,}$/;
	

/ - od tego znaku muszą się zaczynać i kończyć wszystkie wzorce w JavaScripcie
^ - Wzorzec ma się zaczynać z początkiem tekstu
[a-zA-Z]{2,} - Ciąg musi zawierać przynajmniej 2 litery (imie)
\s+ - Po których znajdą się spacje lub tabulatory (min jeden)
[a-zA-Z]{2,} - Po których znajdą się znowu przynajmnej 2 litery (nazwisko)
$ - Wzorzec ma się kończyć z końcem tekstu

Teraz możemy nasz wzór wykorzystać w skrypcie za pomocą metody test:

	var imieINazw = "Marcin Domanski";
	WzorNazwiska = /^[a-zA-Z]{2,}\s[a-zA-Z]{2,}$/;
	if (WzorNazwiska.test(imieINazw)) document.write('Imie i Nazwisko jest OK!')
	

Weryfikacja E-Maila

Jak wiemy, aby adres email był prawidłowy musi spełniać kilka zasad:

Wzór który by opisywał adres mail będzie miał postać:

	var wzorMaila = /^[0-9a-zA-Z_.-]+@[0-9a-zA-Z.-]+\.[a-zA-Z]{2,3}$/
	

/ - od tego znaku muszą się zaczynać i kończyć wszystkie wzorce w JavaScripcie
^ - Wzorzec ma się zaczynać z początkiem tekstu
[0-9a-zA-Z_.-]+ - Następnie badamy nazwę konta, która może składać się z dowolnych znaków (cyfry, litery, .-_ )
@ - Potem sprawdzamy wystąpienia znaku @
[0-9a-zA-Z_.-]+ - Po znaku @ sprawdzamy domenę, która może składać się z takich samych znaków co nazwa konta oprócz znaku _
\. - Po dokumencie musi wystąpić kropka
[a-zA-Z]{2,3} - Po kropce musi wystąpić końcówka domeny, która może się składać wyłącznie z liter i jej długość musi być od 2 do 3 znaków
$ - Wzorzec ma się kończyć z końcem tekstu

Zamiast za każdym razem wpisywać a-zA-Z, możemy uprościć formularz. Na końcu za znakiem / należy wpisać i, co sprawi, że wielkość liter nie będzie brana pod uwagę. Dzięki temu nasze wyrażenie nieco się uprości:

	var wzorMaila = /^[0-9a-z_.-]+@[0-9a-z.-]+\.[a-z]{2,3}$/i
	

Sprawdźmy nasz wzór w przykładowym polu tekstowym (za pomocą metody test):

	var mail = "mar-dom@wp.pl";
	var wzorMaila = /^[0-9a-z_.-]+@[0-9a-z.-]+\.[a-z]{2,3}$/i
	if (wzorMaila.test(mail)) document.write('Mail OK')
	

Atomy i referencja powrotna:

Gdy dokonujemy sprawdzenia według wzorca, możemy nasze części wyrażenia objąć w nawiasy tworząc tak zwane Atomy. Wówczas kolejne Atomy będą zawierać kolejne części znalezionego tekstu, do których będziemy mogli się indywidualnie odwołać:

	var str = "http://www.webreference.com/js/index.php#piosenka?l=2";
	var wzor = str.match(/(\w+:\/\/)([^/]+)([^#?]*)([^?]*)\?*(.+)*/);
	

Wzorzec wyszuka:
(\w+:\/\/) - dowolne litery po których znajduje się ciąg ://
([^/]+) - po których znajduje się ciąg do znaku /
([^#?]*) - po którym znajduje się kolejny ciąg do ? lub #
([^?]*) - po których znajduje się ciąg do ? (czyli jeżeli adres wywołał kotwicę)
\?* - po którym może znajdować się znak ?
(.+)* - po którym może wystąpić ciąg znaków (czyli query string

Po zastosowaniu atomów, możemy się odwoływać do ich treści. Jest on podzielona według naszych atomów, i nazywa się wsteczną referencją. Pierwszym ze sposobów odwoływania do tych treści jest wykorzystanie obiektu RegExp:

    var str = "http://www.webreference.com/js/index.php#piosenka?l=2";
	var wzor = str.match(/(\w+:\/\/)([^/]+)([^#?]*)([^?]*)\?*(.+)*/);
	
    document.write('Badany ciąg: ' + str + '
'); document.write("Wyrazenie z 1 nawiasu: "+ RegExp.$1 +"
"); document.write("Wyrazenie z 2 nawiasu: "+ RegExp.$2 +"
"); document.write("Wyrazenie z 3 nawiasu: "+ RegExp.$3 +"
"); document.write("Wyrazenie z 4 nawiasu: "+ RegExp.$4 +"
"); document.write("Wyrazenie z 5 nawiasu: "+ RegExp.$5 +"
");

Drugi sposób odwoływania się do poszczególnych Atomów polega na podaniu numeru atomu poprzedzonym ukośnikiem:

    var tekst = "FantomasFantomas"
	var wzor = /(Fantomas)\1/;
    tekst.test(wzor);
    

Powyższy wzór korzysta z tej metody.
Pierwszy Atom pasuje do słowa Fantomas, więc wyrażenie (Fantomas)\1 jest równe "FantomasFantomas".

Ostatnią metodą wykorzystania wstecznej referencji jest skorzystanie z metody replace(), która pozwala na korzystanie z numerów poprzedzonych znakiem dolara, oznaczających numer Atomu:

    var tekst = "2010-10-20";
	var wzor = /(\d{4})-(\d{2})-(\d{2})/;
	var zamieniony = tekst.replace(wzor, "$3 $2 $1"); //20-10-2010	
    

Jeżeli chcemy by nasz Atom nie tworzył wstecznej referencji, wtedy musimy rozpocząć jego treść od "?:"

    var wzor = /(\d{4})-(?:\d{2})-(\d{2})/;
   	var zamieniony = tekst.replace(wzor, "$2 $1"); //20-10-2010
    

Referencja powrotna

Jak widzieliśmy w poprzednim przykładzie, kolejne atomy są kolejno numerowane. Ich treść jest przechowywana do późniejszej obróbi i zwie się referencją powrotną.

Podział tekstu na słowa przy pomocy metody split()

To podziału tekstu wykorzystamy metodę split().
Pierwszym parametrem jest wyrażenie regularne, a drugim dodatkowym parametrem tej metody jest maksymalna ilość elementów zwracanych w formie tablicy (IE pomija ten parametr).
Dodatkową uwagę przy stosowaniu tej metody trzeba zwracać na stosowany wzorzec, gdyż np zastosowany poniżej /\W+/ niby zwraca wszystkie litery, ale widać typowo Polskie litery nie są literami... uhh...

	var s = "To jest zdanie doś podzielenia na pojedyńącze slowa"
	var a = s.split(/\W+/); //dzielimy zdanie na słowa (wedle sekwencji nie literowych)
	if (a) {
    	for (x=0; x<a.length; x++) {
			document.write(a[x]+"<BR>");
        }
    }
	

Usuwanie tagów HTML z tekstu

Aby usunąć tagi z jakiegoś tekstu, wystarczy skorzystać z poniższej funkcji, która używa do tego celu wyrażeń regularnych:

	function StripTags(str) {	
		var wzor=new RegExp('<[a-zA-Z/]{1,15}.*?>','g');
		return str.replace(wzor,'');
	}
	

Powyższą funkcję możemy napisać nieco prościej:

	function StripTags(str) {	    
	    var wzor = /<(?:.|\s)*?>/g;
        return str.replace(wzor,'');
    }