Grupy w wyrażeniach regularnych

Kiedyś obiecałem sobie, że przynajmniej raz w roku będę coś tu wrzucał. Tak że teraz publikuję ten wpis jako pomnik mojej prokrastrynacji.

Każdy, kto miał styczność z wyrażeniami regularnymi wie, że temat jest delikatnie rzecz biorąc rozbudowany. Nie jestem ekspertem, ale szacuję, że jest około miliona klas znaków i praktycznie każdy dziwny symbol, jaki jest na klawiaturze ma jakieś swoje znaczenie w języku regexpów. Jakby tego było mało to każde narzędzie ma trochę inną składnię.

Niniejszy artykuł poruszy jedno niewielkie, nie wiem na ile znane (ciężko powiedzieć, ja kiedyś nie znałem) zagadnienie, mianowicie grupy dopasowań. Przyjmuję składnię regexpów w Java/JavaScript, więc polecam wciśnięcie F12 i zabawę w konsoli deweloperskiej w trakcie lektury.

Podstawowa składnia

Do zdefiniowania prostej grupy dopasowań nie trzeba robić nic więcej jak tylko postawić nawiasy w wyrażeniu regularnym.

/(a)bc/

Tyle. Jeśli teraz przepuścimy przez to wyrażenie jakiś pasujący ciąg znaków to wypluje nam ono dwie grupy, grupę 0, która jest całym dopasowaniem i grupę 1, która będzie po prostu zawierać literę a.

Nazwane grupy

Adresacja numerami jest ok, gdy mamy zdefiniowaną jedną, góra dwie grupy. Przy większej liczbie może ucierpieć czytelność, a i bez tego wyrażenia regularne są równie przyjemne do czytania, co książki Paulo Coelho. Żeby sobie ułatwić możemy ponazywać nasze grupy.

/(?<magicNumber>\d+)keyword/

Ok, tu jest tylko jedna grupa, ale nie sensu komplikować przykładu dla idei. W każdym razie teraz możemy się do tej naszej grupy odwoływać po nazwie magicNumber. W tym wypadku to będzie ciąg cyfr (czyli liczba, duh!).

Odwoływanie się do grupy

Co więcej do grupy można się odwołać też w samym wyrażeniu regularnym. Nie wiem po co ktoś miałby to robić, ale tak mi się to spodobało, że napiszę.

/(?<magicNumber>\d+)keyword\d*\k<magicNumber>\d*/

Trochę nam się to skomplikowało to może wytłumaczę, co tu się dzieje. Na początku szukamy tej naszej magicznej liczby, która znajduje się przed słowem keyword. Następnie spodziewamy się ciągu cyfr. Gdzieś wśród tych cyfr musi się znajdować ta magiczna liczba, którą sobie znaleźliśmy na początku, inaczej wyrażenie regularne niczego nie złapie.

Czyli ten ciąg się zmaczuje:
1234keyword865612346789

A ten już niezbyt:
1234keyword999999999999

IDE

Co najlepsze różnego rodzaje IDE i edytory, które pozwalają na Find/Replace po wyrażeniach regularnych, rozumieją też grupy dopasowań.

Załóżmy, że mamy taki kod:

obj.name = "asd";  
obj.age = 12;  
obj.gender = MALE;  

Chcemy zmienić obiekt na powiedzmy mapę. Nie możemy wtedy przypisywać pól, tylko musimy to robić przez metodę put. Jeśli mamy kilkadziesiąt takich przypadków to z ręki wyjdzie nam sporo klikania. Ale oczywiście można to łatwo rozwiązać używając grup!

Find: \.([a-z]+) = ([^;]+)
Replace: .put("$1", $2)

To działa przynajmniej w VSC i IntelliJ. O ile druga część nie jest wyrażeniem regularnym to jest jednak edytor robi z tym coś więcej i wstawia złapane grupy we wskazane miejsca.

No i to chyba tyle w temacie. Szczęśliwego nowego!

P. S. U mnie postanowieniem noworocznym jest ostylowanie jednolinijkowców na blogu. Chyba nie jest tak źle?