Parsare Text și Tokenizare cu RegEx: Construirea unui Lexer și Procesarea de Loguri în Timp Real în Expresii Regulare (RegEx)

Ghid complet de parsare avansată cu RegEx: construirea unui Lexer complet pentru analiză sintactică, extragerea metricilor din loguri Nginx/Apache și funcții callback de înlocuire.

Tipar RegEx
(?P<NUMAR>\d+)|(?P<IDENTIF>[a-zA-Z_]\w*)|(?P<OPERATOR>[+\-*/])

Expresiile regulate nu sunt folosite doar pentru a returna true sau false la un formular de înregistrare. În ingineria software avansată, ele reprezintă fundamentul pentru construirea de lexere (analizoare lexicale pentru compilatoare și limbaje de programare DSL), instrumente de extragere ETL pentru baze de date analitice și parsere de loguri de infrastructură de mare volum.

1. Construirea unui Lexer / Tokenizer în Python cu o singură expresie RegEx
import re
from typing import NamedTuple

class Token(NamedTuple):
    tip: str
    valoare: str
    linie: int
    coloana: int

def tokenizeaza_cod(cod_sursa: str):
    # Combinăm toate regulile limbajului într-o singură expresie cu grupuri denumite:
    token_regex = re.compile(r'''
        (?P       \d+(?:\.\d+)? ) |
        (?P   :=|= )          |
        (?P    [+\-*/] )       |
        (?P     [a-zA-Z_]\w* )  |
        (?P [();,] )        |
        (?P     
 )            |
        (?P        [ 	]+ )        |
        (?P      . )
    ''', re.VERBOSE)

    numar_linie = 1
    inceput_linie = 0

    for m in token_regex.finditer(cod_sursa):
        tip = m.lastgroup
        valoare = m.group()
        coloana = m.start() - inceput_linie
        
        if tip == 'NEWLINE':
            numar_linie += 1
            inceput_linie = m.end()
        elif tip == 'SKIP':
            continue
        elif tip == 'EROARE':
            raise SyntaxError(f"Caracter neașteptat {valoare!r} la linia {numar_linie}, col {coloana}")
        else:
            yield Token(tip, valoare, numar_linie, coloana)

# Testare Lexer:
for tok in tokenizeaza_cod("total = pret * 1.19;
"):
    print(tok)
# Token(tip='IDENTIF', valoare='total', ...)
# Token(tip='ATRIBUIRE', valoare='=', ...)
# Token(tip='IDENTIF', valoare='pret', ...)
# Token(tip='OPERATOR', valoare='*', ...)
# Token(tip='NUMAR', valoare='1.19', ...)

2. Parsarea Logurilor de Server Web (Nginx / Apache Common Log Format)

Formatul standard de loguri web poate fi extras instantaneu într-un dicționar structurat gata pentru stocare în Elasticsearch sau ClickHouse:

Extragerea câmpurilor dintr-o linie de log Nginx
import re

log_line = '192.168.1.105 - - [24/Oct/2026:18:15:30 +0300] "GET /invata/regex/ HTTP/2.0" 200 14820'

regex_nginx = re.compile(r'''
    ^
    (?P         \S+ ) \s+
    \S+ \s+ \S+ \s+
    \[ (?P    [^\]]+ ) \] \s+
    "(?P    [A-Z]+ ) \s+
     (?P      \S+ ) \s+
     (?P  [^"]+ )" \s+
    (?P     \d{3} ) \s+
    (?P     \d+ )
    $
''', re.VERBOSE)

match = regex_nginx.match(log_line)
if match:
    print("Detalii log:", match.groupdict())
# {'ip': '192.168.1.105', 'metoda': 'GET', 'cale': '/invata/regex/', 'status': '200', 'octeti': '14820'}

3. Search & Replace Dinamic cu Funcții Callback

În loc să înlocuiți cu un șir static, atât JavaScript cât și Python permit transmiterea unei funcții ca parametru de înlocuire:

// În JavaScript: convertește toate prețurile din USD în RON la cursul valutar curent:
const text = "Abonament: $10, Opțiune: $25";
const cursUSD = 4.60;

const rezultat = text.replaceAll(/\$(\d+)/g, (match, sumaUSD) => {
    const sumaRON = (parseInt(sumaUSD, 10) * cursUSD).toFixed(0);
    return `${sumaRON} RON`;
});

console.log(rezultat); // "Abonament: 46 RON, Opțiune: 115 RON"