TPerlRegEx Delphi – jak uzyskać drugie dopasowanie wyrażenia regularnego
Pytanie
TPerlRegEx, jak znajść drugie dopasowanie
Odpowiedź Sztucznej Inteligencji
Bezpośrednia odpowiedź na pytanie
- Aby dostać drugie dopasowanie w TPerlRegEx, wywołaj najpierw Match, a następnie MatchAgain. Właściwość MatchedText po udanym MatchAgain zawiera drugie dopasowanie.
- Kluczowe punkty:
- Match daje pierwsze dopasowanie; MatchAgain przechodzi do kolejnego.
- Nie wywołuj ponownie Match, jeśli chcesz iść „dalej” – zazwyczaj rozpocznie wyszukiwanie od początku.
- Zawsze sprawdzaj wartość zwrotną (Boolean) przed odczytem MatchedText.
Szczegółowa analiza problemu
-
Główne aspekty:
- TPerlRegEx działa stanowo: po udanym Match „pozycja wyszukiwania” zostaje ustawiona za końcem bieżącego dopasowania. MatchAgain kontynuuje od tej pozycji.
- Przepływ dla 2. dopasowania: Match → (sukces) → MatchAgain → (sukces) → MatchedText to „drugie”.
- Zmiana Subject, RegEx lub niektórych opcji resetuje wewnętrzną pozycję – po takich zmianach trzeba znów zacząć od Match.
-
Teoretyczne podstawy:
- TPerlRegEx opiera się na silniku PCRE (Perl-Compatible Regular Expressions). W trybie „globalnym” iteracja po kolejnych dopasowaniach jest realizowana właśnie przez MatchAgain (odpowiednik /g w Perlu).
-
Praktyczne zastosowania:
- Szybkie pobranie konkretnego n-tego dopasowania (np. drugiego) bez budowania listy wszystkich wyników.
- Przetwarzanie strumieniowe: pętla Match/MatchAgain aż do wyczerpania dopasowań.
Przykłady (Delphi):
-
Drugie dopasowanie wprost
uses
PerlRegEx; // lub System.RegularExpressionsCore, zależnie od projektu
var
R: TPerlRegEx;
begin
R := TPerlRegEx.Create;
try
R.Subject := 'abc 123 def 456 ghi 789';
R.RegEx := '\d+';
if R.Match then // pierwsze: 123
if R.MatchAgain then // drugie: 456
ShowMessage('Drugie: ' + R.MatchedText)
else
ShowMessage('Brak drugiego dopasowania')
else
ShowMessage('Brak dopasowań');
finally
R.Free;
end;
end;
-
Ogólna funkcja: n-te dopasowanie (N=2 → drugie)
function FindNthMatch(const S, Pattern: string; N: Integer; out Value: string): Boolean;
var
R: TPerlRegEx;
i: Integer;
begin
Result := False;
Value := '';
if N < 1 then Exit;
R := TPerlRegEx.Create;
try
R.Subject := S;
R.RegEx := Pattern;
if not R.Match then Exit; // brak 1.
i := 1;
while i < N do
begin
if not R.MatchAgain then Exit; // nie ma kolejnego
Inc(i);
end;
Value := R.MatchedText;
Result := True;
finally
R.Free;
end;
end;
-
Alternatywa (nowsze API): TRegEx.Matches (kolekcja)
uses
System.RegularExpressions;
var
M: TMatchCollection;
begin
M := TRegEx.Matches('abc 123 def 456', '\d+');
if M.Count >= 2 then
ShowMessage('Drugie: ' + M.Item[1].Value);
end;
Uwagi techniczne:
- MatchedOffset w TPerlRegEx jest 1‑indeksowany (pozycje liczone od 1), MatchedLength to długość w znakach.
- Jeżeli wzorzec może dopasować pusty ciąg (zero-length match), pilnuj, by przenieść pozycję ręcznie lub modyfikować wzorzec (inaczej można „utknąć” na tym samym miejscu). Bezpieczna praktyka: projektować wzorce tak, by nie dawały pustych dopasowań w iteracji globalnej.
Aktualne informacje i trendy
- W nowoczesnych wersjach Delphi wygodniejsze w wielu przypadkach jest TRegEx (System.RegularExpressions) z kolekcją TMatchCollection oraz enumeracją dopasowań. Ułatwia to indeksowanie (np. M[1] jako „drugie”).
- TPerlRegEx pozostaje przydatny w projektach legacy lub tam, gdzie wymagana jest pełna zgodność ze składnią PCRE i zachowaniem „perlowym”.
Wspierające wyjaśnienia i detale
- Różnice nazw właściwości: w zależności od wersji biblioteki możesz spotkać SubExpressions[] (TPerlRegEx) lub Groups (w strukturach TRegEx/TMatch). Logika pozostaje ta sama: indeks 0 to całe dopasowanie, >0 to grupy w nawiasach.
- Restart wyszukiwania: ponowne wywołanie Match po MatchAgain (bez zmian Subject/RegEx) zwykle zaczyna od początku. Do przechodzenia „dalej” używaj MatchAgain w pętli.
Aspekty etyczne i prawne
- TPerlRegEx opiera się na PCRE, które jest rozpowszechniane na licencjach liberalnych (BSD‑like). W projektach komercyjnych zweryfikuj zgodność licencji użytej wersji PCRE/biblioteki.
Praktyczne wskazówki
- Twórz osobną instancję TPerlRegEx na wątek (brak współdzielenia stanu).
- Nie modyfikuj Subject ani RegEx między Match a MatchAgain, jeśli chcesz kontynuować iterację.
- Jeśli chcesz jedynie „drugie” dopasowanie i nic więcej, zakończ iterację natychmiast po jego znalezieniu (oszczędność czasu).
- Do debugowania wzorców używaj małych próbek i testów jednostkowych (edge‑case’y: brak dopasowań, jedno dopasowanie, dopasowania nakładające się, puste dopasowania).
Ewentualne zastrzeżenia lub uwagi dodatkowe
- Szczegóły interfejsu mogą się nieznacznie różnić między jednostką PerlRegEx a System.RegularExpressionsCore (nazwy właściwości, dostępność metod pomocniczych).
- Puste dopasowania i dopasowania nachodzące: standardowa iteracja MatchAgain nie zwraca dopasowań zachodzących na siebie; do takich przypadków trzeba użyć innej strategii (np. ręczne zwiększanie pozycji startowej i ponowne Match).
Sugestie dalszych badań
- RAD Studio DocWiki: System.RegularExpressionsCore.TPerlRegEx (opis Match/MatchAgain, MatchedOffset/MatchedLength).
- RAD Studio DocWiki: System.RegularExpressions.TRegEx (Matches, TMatch, NextMatch).
- Dokumentacja PCRE (sekcje o dopasowaniach globalnych i dopasowaniach pustych).
Krótkie podsumowanie
- Najprościej: wywołaj Match, potem MatchAgain; jeśli oba zwrócą True, MatchedText po MatchAgain to drugie dopasowanie.
- Dla n‑tego dopasowania: pętla z kolejnymi MatchAgain aż do osiągnięcia żądanego indeksu.
- W nowszym API rozważ TRegEx.Matches i odczyt drugiego elementu kolekcji (indeks 1).
Zastrzeżenie: Odpowiedzi udzielone przez sztuczną inteligencję (model językowy) mogą być niedokładne i wprowadzające w błąd. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi powinny być zweryfikowane przez użytkownika.
Zadaj dodatkowe pytanie Sztucznej Inteligencji