1. Regex - podstawy
Tags: regex, javascript, beginners, webdev
Published: 2022-09-09 17:09:45

# Co to jest wyrażenie regularne?

Wyrażenie regularne (**regexp**, **reg**ular **exp**ression) to wzorzec na postawie którego wyszukujemy określony zbiór znaków w danym ciągu tekstowym.

#### 1. Proste wzorce

Wyrażenie regularne możemy pisać w różnoraki sposób, jednym z nich jest użycie **prostych wzorców**, czyli użycie jako wzorca konkretnego ciągu tekstowego.

> regex: Ala ma kota.
> string: Daniel ma psa, a **Ala ma kota.**

#### 2. Znaki specjalne

---
###### Adnotacja: W przykładach pokazuję wyszukania z użyciem flagi **\g (global)**. Więcej o niej w sekcji Flagi.
---

Sposób pierwszy możemy uzupełnić lub zastąpić sposobem drugim, czyli stworzyć wzorzec za pomocą znaków specjalnych. Oto one:

- **[xyz]** - Zbiór znaków. Oznacza, że w ciągu tekstowym będziemy poszukiwać jeden ze znaków podanych między nawiasami kwadratowymi.
Możemy dany zbiór opisać także jako zakres np. [a-c], oznacza on, że szukamy jednego ze znaków w zakresie tj. a, b lub c.

> regex: [a-c0-3]
> string: Eugeniusz w<u>a</u>l<u>c</u>zył z 4<u>3</u> wojownik<u>a</u>mi.

- **[^xyz]** - Negacja zbioru znaków. W danym ciągu tekstowym nie będziemy szukać żadnego z podanych znaków.

> regex: [^0-3]
> string: 1333,00<u>4</u>

- **.** - Dopasowuje każdy rodzaj znaku oprócz znaków łamania linii(\n, \r). Natomiast w zbiorze znaków traci swoją właściwość i dopasowuje wtedy znak kropki.

> regex: [a-b.].
> string: <u>.c</u>.e

> regex: .
> string: <u>E</u>ugeniusz

- **\d** - Dopasowuje każdy znak liczbowy, jest równoznaczny z [0-9.
 
- **\D** - Negacja znaku liczbowego, dopasowuje każdy znak który nie jest cyfrą. Równoznaczny z [^0-9].

- **\w** - Dopasowuje każdy alfanumeryczny znak z podstawowego łacińskiego alfabetu. Równoznaczne z [A-Za-z0-9_].

- **\W** - Negacja \w. Dopasowuje wszystko co nie jest znakiem z podstawowego łacińskiego alfabetu. Równoznaczne z [^A-Za-z0-9_].

- **\s** - Dopasowuje pojedynczy biały znak(spacja, tab, enter).

- **\S** - Dopasowuje każdy **NIE** biały znak. 

Z powyższych opisów możemy dojść do wniosku, że skrócony opis wzorca zawierający wielką literę jest negacją wzorca napisanego z użyciem małej litery(\D - \d). 

Więcej znaków specjalnych znajdziecie [tutaj](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes#types).

#### 3. Grupowanie

Przy tworzeniu wyrażeń regularnych możemy się posługiwać grupowaniem, jest to zwłaszcza przydatne gdy oprócz pożądanego ciągu tekstowego, chcemy mieć także dostęp do jego poszczególnych składowych.

> regex: (\d*) (\w*) (\d*)
> string: 25 Stycznia 2015

> match 0 - 25 Stycznia 2015
> group 1 - 25
> group 2 - Stycznia
> group 3 - 2015

W tym przykładzie widzimy jak znalezione grupy są uwzględnione na kolejnych miejscach w tablicy.

```javascript
const re = new RegExp(/(\d*) (\w*) (\d*)/);
const string = '25 Stycznia 2015';
const found = string.match(re);
console.log(found);

> ["25 Stycznia 2015", "25", "Stycznia", "2015"]
```

#### 3. Kwantyfikatory

W składni wyrażeń regularnych wykorzystujemy także kwantyfikatory, które określają nam ilość znaków jakie chcemy mieć dopasowane wykorzystując dany wzorzec. Oto ich lista z opisem jak je stosować:

- **x*** - dopasowuje wzorzec x, zero lub więcej razy.

W przykładzie widzimy, że nie używając kwantyfikatora gwiazdki dopasuje nam się tylko jeden znak alfanumeryczny(w tym przypadku mała litera e).

> regex: ([A-Z])\w*
> string: <u>Res</u>

> regex: ([A-Z])\w
> string: <u>Re</u>s<u>

Natomiast poniżej możemy zauważyć, że mimo braku znaku z zakresu [a-e] pomiędzy literami A i l, to ciąg tekstowy <u>Alm</u> zostanie dopasowany, ze względu na to, że kwantyfikator gwiazdki dopuszcza brak występowania danego znaku.

> regex: A[a-e]*lm
> string: <u>Alm</u>ost done.


- **x+** - Dopasowuje wzorzec x, jeden lub więcej razy.

- **x?** - dopasowuje wzorzec x, zero lub jeden raz.

- **x{n}** - Dopasowuje wzorzec x "n" razy.

> regex: \d{2}
> string: <u>12</u>3

- **x{n,}** - Dopasowuje wzorzec x minimum "n" razy.

- **x{n,m}** - Dopasowuje wzorzec x minimum "n" razy, ale nie więcej niż "m" razy.


#### 4. Podstawowe asercje

Asercje w wyrażeniach regularnych odpowiadają za "granice", czyli początki i końce linii oraz słów, na ich bazie możemy ustalić w którym miejscu dopasowanie ma mieć miejsce(na początku ciągu tekstowego, na jego końcu, po danym znaku lub przed danym znakiem). Typy asercji:

- **^** - Dopasowuje początek ciągu tekstowego.
- **$** - Dopasowuje koniec ciągu tekstowego.

> regex: ^\d*
> string: <u>481</u> 234 233

> regex: \d*$
> string: 481 234 <u>233</u>

- **\b** - Granica ciągu tekstowego o długości zerowej. Dopasowuje pozycję między znakiem alfanumerycznym(\w), a negacją znaku alfanumerycznego(\W). 

> regex: \b\d{3}\b
> string: 4813 <u>234</u> 2334

W podanym przykładzie nie zostaną dopasowane inne liczby niż <u>234</u>(spacja nie jest znakiem alfanumerycznym w rozumieniu wyrażeń regularnych, więc zostaje dopasowana jako granica dopasowanego ciągu tekstowego), ponieważ w ciągu 4183, jest znak liczbowy(4), a wzorzec wymaga znaku niealfanumerycznego, tak też jest w związku z liczbą 2334.

Podam kolejny przykład, bardziej skomplikowany:

> regex: \bcat\b
> string: The <u>cat</u> scattered.
> string: The$<u>cat</u>$scattered.

Słowo cat zostanie dopasowane gdy jest pomiędzy dwoma spacjami, natomiast już nie jeżeli jest w słowie s**cat**tered. Zostanie również dopasowane pomiędzy znakami dolara.
Dlaczego tak jest? Otóż zarówno spacja jak i znak $ nie są znakami alfanumerycznymi lub znakiem podkreślenia(który jest wyjątkiem), więc nie stanowią części słowa cat. 

Głównym zadaniem asercji **\b** jest właśnie ustanowienie granicy rozpoczęcia lub zakończenia danego słowa. Możemy powiedzieć, że chcemy, żeby dane słowo było osobnym bytem, a nie częścią wyrazu.

- **\B** - Dopasowuje pozycję, która nie jest granicą słowa.

> regex: \B.*
> string: n<u>oon</u>

> regex: s\B
> string: <u>s</u>ells

W tym przypadku nie zostanie dopasowany ostatni znak **s**, ponieważ tuż po nim mamy naturalną granicę słowa - spację.


#### 5. Flagi

Wyrażenia regularne posiadają flagi, które możemy użyć aby rozszerzyć ich funkcjonalność, można je używać pojedynczo lub łącznie, kolejność zapisu nie ma znaczenia.

- **g** - Globalne wyszukiwanie, warunkuje, że w danym ciągu tekstowym będą znalezione wszystkie możliwe dopasowania. Metoda działania opiera się na tym, że po pierwszym dopasowaniu nie następuje koniec działania programu, ale rozpoczyna się kolejne wyszukiwanie od końca poprzedniego dopasowania.

- **i** - Case-insensitive, flaga warunkująca, że wyszukujemy nie zwracając uwagę na wielkość znaków.

- **m** - Użycie definiuje, że asercje **^** i **$**, działają na bazie nowych linii, a nie całości ciągu tekstowego.

> regex: /^\d{3}$/mg
> string: 
> <u>123</u>
> <u>334</u>

Więcej o flagach możecie przeczytać [tutaj](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#advanced_searching_with_flags).


W kolejnym artykule opiszę użycie referencji zwrotnych, lookahead, lookbehind oraz pozostałych możliwości grupowań.