
Dziś omówimy jeden z nieco trudniejszych tematów, mianowicie wyrażenia regularne. Oczywiście naprawdę trudne są te najbardziej rozbudowane i zaawansowane wyrażenia. Wszystko jednak rekompensuje się w możliwościach, jakie daje to narzędzie!
Wyrażenia regularne w JavaScript
Wyrażenia regularne (Regular Expressions) są sposobem zapisania wzorca, z którym mogą być porównywane ciągi znaków, celem sprawdzania czy dany ciąg pasuje do podanego wzorca, a także celem wyszukiwania podciągów i ewentualnej zmiany bądź weryfikacji, itp.
Przykładowo można podać listę znaków które mogą pojawić się na danej pozycji (wewnątrz nawiasów kwadratowych):
// po literze "a" ma pojawić się cyfra od 0 do 7: a[01234567]
Jeśli więc po znaku „a” pojawi się któraś z podanych cyfr, wzorzec zostanie dopasowany.
Istnieją także wersje skrócone tzn. z podaniem zakresów: a[0-7], czy też [a-z], [A-Z], itp.
Możliwe jest zanegowanie listy, poprzez znak ^:
[^0-9a-zA-Z]
Sekwencje specjalne
Dostępne są specjalne sekwencje, zastępujące predefiniowane zestawy znaków:
– \d – dowolna cyfra: [0-9]
– \D – dowolny znak nie będący cyfrą: [^0-9]
– \w – dowolna cyfra, litera (mała lub duża) lub znak podkreślenia: [0-9a-zA-Z_]
– \W – dowolny znak nie będący cyfrą, literą ani znakiem podkreślenia: [^0-9a-zA-Z_]
– \s – dowolny biały znak: [ \t\r\n\v\f]
– \S – dowolny znak nie-biały: [^ \t\r\n\v\f]
Znaki specjalne:
– \t – znak tabulacji poziomej (0x09)
– \v – znak tabulacji pionowej (0x0B)
– \r – „powrót karetki” (0x0D)
– \n – znak nowej linii (0x0A)
– \f – wysunięcie strony (0x0C)
Powtórzenia wzorca
W trakcie pisania wyrażeń regularnych często zdarza się, że pewien fragment wzorca powinien się powtórzyć. Służą do tego specjalne kwalifikatory, które umieszczone w wyrażeniu regularnym określają ile razy może (lub musi) powtórzyć się element znajdujący się tuż przed nim.
Oto lista:
– {n} – dokładnie n wystąpień poprzedzającego wyrażenia
– {n,} – n lub więcej wystąpień poprzedzającego wyrażenia
– {n,m} – od n do m wystąpień poprzedzającego wyrażenia
– ? – element poprzedzający jest opcjonalny (może wystąpić 0 lub 1 raz)
– + – element poprzedzający może wystąpić jeden lub więcej razy
– * – element poprzedzający może wystąpić zero lub więcej razy
Przykład:
/t{1,2}/ pasuje do wyrazów tekście mających 't', 'tt'
Znaki dosłowne (literalne) – czyli zwykłe znaki, tak umieszczone mają dokładnie takie znaczenie, np.:
/a/ pasuje do 'a' w tekście "access"
Flagi
Istnieją trzy flagi, których można użyć w wyrażeniach regularnych JavaScript:
– g – szukaj globalnie – wyrażenie regularne szuka w tekście ciągów pasujących do wzoru tworząc tablicę wszystkich wystąpień tych ciągów
– i – ignoruj wielkość liter
– m – wieloliniowe wejście, że znak początku tekstu (^) i końca tekstu ($) są także w kolejnych liniach znakami początku i końca linii; słowem przetwarzanie ma dotyczyć ciągu zawierającego wiele wierszy
Przykład:
/fooBar/i;
Przejdźmy do użycia wyrażeń regularnych w JavaScript
Wyrażenie regularne w JS może zostać utworzone na dwa sposoby:
1. Poprzez wykorzystanie literału,
2. Poprzez formalne wywołanie konstruktora RegExp.
W pierwszym przypadku należy umieścić w kodzie wyrażenie zawarte pomiędzy prawymi ukośnikami, które może być dodatkowo zakończone znacznikami (flagami), w postaci:
/wyrażenie/[flagi]
W przypadku drugim wyrażenie tworzone jest za pomocą następującej konstrukcji:
new RegExp("wyrazenie"[, "flagi"]) // a /(ab)+c/gi // b new RegExp("(ab)+c", "gi")
Wyrażenia oznaczone w przykładzie jako a i b są równoznaczne.
Jak widać nie umieszczamy wyrażenia regularnego cudzysłowie lub w apostrofach, ale pomiędzy znakami / oraz /.
Metody obiektów typu RegExp i String do obsługi wyrażeń regularnych
RegExp.compile(wyrazenie[, flagi]) – metoda compile dokonuje wewnętrznej kompilacji wyrażenia, co pozwala na późniejsze szybsze jego przetwarzanie. Wyrażenie może zawierać flagi i, g, m, których znaczenie jest takie samo jak w przypadku konstrukcji nowego wyrażenia.
RegExp.exec(wzorzec) – wykonuje przeszukanie ciągu str, wykorzystując wzorzec zawarty w wyrażeniu regularnym i zwraca tablicę wynikową.
Przykład – użycie metody RegExp.exec():
// przykład 1 var result = /s(amp)le/i.exec("My Sample Text"); // wynik: "Sample","amp" // przykład 2 var str = "Ola ma kota, a Ala ma psa."; var regexp = /Ala/; var wynik = regexp.exec(str); for (index in wynik){ document.write("wynik[" + index + "] = " + wynik[index] + "<br />"); }
RegExp.test(wzorzec) – zwraca true, jeśli ciąg znaków zawiera wzorzec pasujący do wyrażenia, false jeśli nie zawiera.
Przykład – użycie metody RegExp.test():
// przykład 1 /ala/i.test("Ola ma kota, a Ala ma psa."); //wynik: true // przykład 2 var pasuje = /sample/.test("My Sample text"); // wynik: false (ze względu na wielkość liter / brak flagi "i")
String.match(wzorzec) – metoda ta porównuje ciąg znaków z wyrażeniem regularnym, celem dopasowania.
Przykład – uzycie String.match():
var str = "Programming with RoR".match(/r?or?/gi); // wynik dopasowania: ["ro","RoR"]
String.search(wzorzec) – porównuje wyrażenie regularne z ciągiem znaków i zwraca indeks początku pasującego ciągu lub -1 jeżeli nic nie dopasuje.
Przykład – użycie String.search():
var idx = "Looking for JavaScript tips...".search(/for/); // wynik: 8
String.replace(wzorzec, string) – zamienia miejsca, w których nastąpiło dopasowanie do wzorca.
Przykład – użycie String.replace():
// przykład 1 var str = "Ala ma kota".replace(/Ala/i, 'Ola'); // wynik: Ola ma kota // przykład 2 var re = /(\w+)\s(\w+)/; var str = "Jan Kowalski"; var newstr = str.replace(re, "$2, $1"); document.write(newstr); // wynik: "Kowalski, Jan"
Skrypt używa symboli „$1” i „$2” do oznaczenia wyników odpowiadających im nawiasów we wzorze wyrażenia regularnego.
String.split(wzorzec) – metoda rozbija (dzieli) ciąg znaków do postaci tablicy w miejscach gdzie dopasuje wzór.
Przykład – użycie String.split():
var str = "I am happy!".split(/\s/g); // wynik: ["I","am","happy"]
I w tym momencie mamy kompletną skrzynkę narzędziową, aby pracować z wyrażeniami regularnymi w JavaScript.
Na koniec kilka przykładów praktycznych.
Przykład – parsowanie adresu URL:
var parse_url = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/; var url = "http://www.serwer.com:80/stuff?q#fragment"; var result = parse_url.exec(url); var names = ['url', 'protokol', 'ukosniki', 'serwer', 'port', 'path', 'zapytanie', 'zakotwiczenie']; var blanks = ' '; var i; for (i = 0; i < names.length; i += 1) { document.writeln(names[i] + ':' + blanks.substring( names[i].length), result[i]); }
Przykład – usuwanie łamania linii z ciągu znaków (np.: nagłówka strony):
var reg = new RegExp("(<br| /)>", "i"); sub_header_content = header_content.replace(reg, "");
Kolejne dwa przykłady, to funkcje, które już na stałe wchodzą w skład bibliotek dołączanych przeze mnie do niektórych projektów, nad którymi pracowałem.
Obie służą do walidacji wartości podawanych w formularzach. Pierwsza sprawdza, czy wpisano tylko liczby. Druga to walidacja adresu e-mail.
Przykład – walidator pozwalający wpisać tyko liczby:
/** * Allow: 0-9 digits only */ function onlyDigitsUtil(input) { var out = ""; var dt = 0; var result = ""; var regExp = /[0-9]+/; result = regExp.exec(input); if (result !== null) { dt = result.length; for (var i = 0; i < dt; i++) { out += result[i]; } } return out; }
Przykład – walidacja adresu e-mail w JavaScript:
/** * Email address - quick check */ function emailValidatorQuickTest(fieldVal) { // pattern var filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; if (!filter.test(fieldVal)) { return false; } return true; }
Mały test dla chętnych i dociekliwych: jak zmienić wyrażenie regularne (var filter), aby było znacznie krótsze? Podpowiedź: flaga /i.
Podsumowanie
Same wyrażenia regularne to temat na całą książkę. Mam nadzieję, że ten krótki artykuł wystarczy do sprawnego posługiwania się wyrażeniami regularnymi w JavaScript.
Dla czujących niedosyt, polecam podstronę Regular Expressions w MDN, szczególnie godna uwagi jest tabela z listą i opisem znaków specjalnych, używanych przy wyrażeniach regularnych.
/Dziękuję za uwagę./