Wyrażenie regularne potrafi skrócić kilkanaście linii kodu do jednego wzorca. Oszczędność miejsca nie zawsze oznacza oszczędność pracy. Po kilku miesiącach nikt nie pamięta, dlaczego grupa jest opcjonalna, które formaty miały być odrzucone i czy dodanie alternatywy zmieni wydajność. Utrzymywalny regex powinien być traktowany jak kod produkcyjny: ma jedno zadanie, opisane założenia, testy i granicę złożoności.
Jeden wzorzec powinien mieć jeden cel
Regex dobrze sprawdza strukturę albo wyodrębnia fragmenty. Nie musi jednocześnie implementować całego modelu domenowego. Format daty YYYY-MM-DD można rozpoznać wzorcem, lecz istnienie 29 lutego lepiej sprawdzi biblioteka kalendarza.
Rozdzielenie daje lepsze komunikaty: zły format, nieistniejąca data i niedozwolony okres to inne problemy. Jeden mega-regex zwykle zwraca tylko false.
Rodzaj dopasowania musi być jawny
Walidacja najczęściej potrzebuje full match, wyszukiwanie fragmentu. Brak kotwic może zaakceptować poprawny podciąg z dodatkowymi znakami. Full-match API pokazuje intencję czytelniej niż przypadkowe użycie funkcji search.
Tryb multiline zmienia zachowanie początku i końca. Flagi powinny znajdować się obok wzorca i być widoczne w review.
Precyzyjna klasa jest lepsza od dowolnej kropki
.* niewiele mówi o dozwolonej treści i może przejść przez kilka separatorów. Klasa wykluczająca granicę albo jawny limit długości lepiej opisuje format i zwykle ogranicza koszt.
Skróty znakowe również wymagają decyzji. ASCII ID i naturalne imię mają inne potrzeby Unicode. Wzorzec powinien odzwierciedlać kontrakt, nie wygodny skrót.
Nazwane grupy tworzą czytelny interfejs
Grupy year, host i slug mówią więcej niż pozycje 1, 2 i 3. Non-capturing groups należy stosować, gdy nawias służy tylko do struktury. Wynik nie zmienia wtedy kształtu przy refactorze.
Kod musi obsługiwać brak grup opcjonalnych. Sam sukces match nie oznacza, że każdy capture ma wartość.
Tryb free-spacing pozwala formatować wzorzec
Wiele silników pozwala rozłożyć regex na linie i dodać komentarze. Długi format protokołu może wtedy mieć osobny blok dla prefiksu, identyfikatora i suffixu. Review staje się podobne do zwykłego kodu.
Literalne spacje i whitespace w klasach nadal wymagają uwagi. Flaga musi podróżować razem z patternem, inaczej skopiowana wersja zmieni znaczenie.
Najkrótszy zapis nie zawsze jest najlepszy
Wspólne prefiksy alternatyw warto grupować, ale nadmierna kompresja tworzy zagadkę. Kilka dodatkowych znaków jest rozsądną ceną, jeśli reviewer potrafi szybko wymienić dozwolone przypadki.
Regex nie bierze udziału w konkursie code golf. Miarą jakości jest poprawna zmiana bez niezamierzonego rozszerzenia języka.
Dane dynamiczne muszą być cytowane
Wartość użytkownika wstawiona bezpośrednio do wzorca może zawierać kropkę, nawias lub quantifier i stać się aktywną składnią. Biblioteki oferują funkcję quote lub escape do tworzenia literału.
Nawet poprawnie escaped tysiące alternatyw mogą być kosztowne. Dla dużego słownika lepszy będzie trie, indeks lub zwykła mapa.
Testy są rzeczywistą specyfikacją
Pozytywne przypadki pokazują przeznaczenie, negatywne chronią granice. Szczególnie wartościowe są dane prawie poprawne: jeden znak za dużo, brak końca, Unicode zamiast ASCII, newline i bardzo długa sekwencja.
Każdy błąd produkcyjny powinien zostać fixture regresji. Bez konkretnego inputu kolejna „czytelniejsza” wersja może przywrócić problem.
Property testing bada większą przestrzeń
Generator może tworzyć losowe stringi i sprawdzać własności: wykonanie kończy się w limicie, poprawnie sformatowana wartość zostaje zaakceptowana, a parse i format dają stabilny round trip. Uzupełnia to ręczne przykłady.
Fuzzing pomaga znaleźć zarówno błędne wyniki, jak i wyjątkowo wolne ścieżki na niezaufanym wejściu.
Engine i wersja należą do kontraktu
Pattern z PCRE nie musi działać w JavaScript. Unicode i capture również mogą się różnić. Dokumentacja powinna podawać język, bibliotekę oraz flags. Migracja wymaga uruchomienia tych samych fixtures w nowym środowisku.
Online tester jest notatnikiem, nie dowodem zachowania produkcji. Delimitery i escape stringa mogą być inne.
Wzorce powinny być wersjonowane razem z kodem
Regex zapisany wyłącznie w panelu lub zewnętrznej dokumentacji trudno powiązać z release, testami i incydentem. Wzorzec produkcyjny powinien mieć właściciela, review oraz historię zmian. Jeżeli musi być konfigurowalny, konfiguracja potrzebuje walidacji i audytu.
Zmiana dopuszczanego formatu jest zmianą kontraktu danych. Przed wdrożeniem warto sprawdzić istniejące rekordy, aby nowa walidacja nie zablokowała edycji poprawnych wcześniej wartości.
Przykłady w komentarzu nie zastępują automatycznych testów
Komentarz pomaga zrozumieć intencję, lecz szybko się dezaktualizuje. Table-driven tests powinny zawierać input, oczekiwany wynik i przechwycone grupy. Dzięki temu uproszczenie wzorca ma natychmiastową informację zwrotną.
Testy należy wykonywać także na docelowych flagach oraz pełnej funkcji wywołującej, ponieważ search, match i replace mogą używać tej samej regex w odmienny sposób.
Walidację warto dzielić na etapy
Najpierw limit długości, potem dozwolone znaki, następnie struktura i na końcu reguły domeny. Każdy etap daje konkretną wiadomość i zmniejsza koszt następnego.
To podejście jest często bezpieczniejsze niż jeden wzorzec z wieloma lookarounds. Kod jest dłuższy, ale odpowiedzialności są jawne.
Pełne języki potrzebują parsera
HTML, JSON i kod programu mają nesting, escape i error recovery. Dedykowany parser rozumie strukturę. Regex może znaleźć lokalny token, lecz nie powinien udawać całej gramatyki.
Zmiana narzędzia nie jest porażką. Jest właściwym rozdzieleniem pattern matching od interpretacji danych.
Review potrzebuje krótkiego opisu intencji
Przy nietrywialnym patternie warto zapisać oczekiwany format, zakres i reguły celowo pozostawione poza regex. Link do tymczasowego testera nie zastępuje testów w repozytorium.
Utrzymywalny regex jest ograniczony, zakotwiczony, przetestowany i szybki dla najgorszego dopuszczalnego inputu. Dzięki temu kolejna osoba może go zmienić bez zgadywania.