(?=…) și (?!…) (Positive / Negative Lookahead) în Expresii Regulare (RegEx)

Lookaround și flag-uri PCRE / ECMAScript / Python

Verifică dacă poziția curentă este urmată (?=...) sau NU este urmată (?!...) de un anumit șablon, fără a consuma caracterele.

Tipar RegEx
X(?=Y)   |   X(?!Y)   |   ^(?=.*d)(?=.*[A-Z]).{8,}$

Ce face (?=...) și (?!...) (Positive / Negative Lookahead)

Aserțiunile Lookahead („privire înainte”) verifică ce urmează în dreapta poziției curente din text, dar sunt aserțiuni de lungime zero (zero-width assertions): ele doar returnează adevărat/fals, fără a avansa cursorul și fără a include acele caractere în potrivirea finală.

Există două variante: Positive Lookahead (?=Y) cere ca în dreapta să urmeze șablonul Y, iar Negative Lookahead (?!Y) cere ca în dreapta să nu urmeze șablonul Y. Deoarece nu consumă caractere, poți înlănțui mai multe lookahead-uri la începutul expresiei (^(?=cond1)(?=cond2)(?=cond3)) pentru a verifica simultan mai multe reguli (tehnica standard pentru validarea parolelor).

Variante și sintaxă asociată

Expresie / Simbol Descriere
X(?=Y) Positive Lookahead: potrivește X doar dacă este urmat imediat de Y (Y nu face parte din match).
X(?!Y) Negative Lookahead: potrivește X doar dacă NU este urmat imediat de Y.
(?=.*\d) Verifică de la poziția curentă că undeva mai încolo pe linie există cel puțin o cifră.
^(?!.*admin).*$ Verifică că întregul rând NU conține cuvântul „admin” nicăieri în el.

Exemple

Exemplul 1: Extragerea doar a sumelor exprimate în RON / lei cu Positive Lookahead

Vrem să extragem doar numărul (ex. 250), dar numai dacă după el urmează lei sau RON.

Expresie: /\b\d+(?=\s*(?:lei|RON)\b)/gi
Text:     "Produsul costă 250 lei (sau 50 EUR), iar transportul este 15 RON."

Potriviri găsite (Matches)

Match 1: "250"
Match 2: "15"
(50 este ignorat fiindcă este urmat de EUR, iar cuvintele "lei"/"RON" nu sunt incluse în match)

Exemplul 2: Formatarea unui număr cu puncte pentru mii (1234567 → 1.234.567)

Căutăm fiecare poziție (nu caracter!) care nu este la începutul cuvântului (\B) și este urmată de un multiplu de 3 cifre.

// JavaScript:
const suma = "1250900";
const formatat = suma.replace(/\B(?=(\d{3})+(?!\d))/g, ".");

Potriviri găsite (Matches)

"1.250.900"

Greșeli frecvente

  • Uitarea faptului că un lookahead nu consumă caractere: dacă scrii /(?=http)https:\/\/\S+/, este valid (deoarece https... începe cu http), dar dacă scrii /(?=https:\/\/)www\.\S+/, expresia este imposibilă (cere ca același loc din șir să înceapă simultan și cu https://, și cu www.!).
  • Confuzia între X(?!Y) (negative lookahead) și X[^Y] (set negat): q(?!u) potrivește q și la finalul cuvântului Iraq, pe când q[^u] eșuează fiindcă cere obligatoriu un caracter după q.

Simboluri și rețete înrudite