Estrazione del testo (PEG e regex)
Quando automatizzi il browser, incontri spesso dati “grezzi”: testo formattato in modo incoerente, con errori di battitura o con tipi di informazioni diversi mescolati in un’unica stringa.
JavaScript e Lua si affidano alle espressioni regolari (regex) per questo compito, mentre il motore Janet di Guida include un motore Parsing Expression Grammar (PEG) integrato. Le PEG sono una potente alternativa alle regex e rendono l’estrazione di testo complessa più facile da leggere, scrivere e mantenere.
Il problema delle regex
Sezione intitolata “Il problema delle regex”Le regex sono eccellenti per pattern semplici, ma diventano rapidamente illeggibili, quasi un linguaggio a se stante molto poco propenso a futura manutenzione, quando si lavora con strutture complesse o annidate.
Immagina di estrarre prezzo e ID di un prodotto da una stringa non strutturata come "Articolo: SuperWidget (ID: 98765) - Solo $49.99 oggi!".
JavaScript (regex)
Sezione intitolata “JavaScript (regex)”const text = "Articolo: SuperWidget (ID: 98765) - Solo $49.99 oggi!";
// La regex è densa e si affida a gruppi di cattura estratti per indiceconst regex = /\\(ID:\\s*(\\d+)\\).*?\\$([0-9.]+)/;const match = text.match(regex);
if (match) { const id = match[1]; const price = match[2]; g.log(`ID trovato: ${id}, prezzo: ${price}`);}Funziona, ma la regex è fragile. Se il formato cambia anche di poco, la regex fallisce; modificarla richiede un notevole sforzo mentale.
L’approccio Janet (PEG)
Sezione intitolata “L’approccio Janet (PEG)”Il modulo peg di Janet permette di costruire parser in modo composizionale. Invece di una singola stringa enorme e criptica, definisci una grammatica come dizionario di regole leggibili.
Janet (PEG)
Sezione intitolata “Janet (PEG)”(def text "Articolo: SuperWidget (ID: 98765) - Solo $49.99 oggi!")
# Definisci una grammatica pulita e composizionale(def product-grammar (peg/compile ~{:id-rule (sequence "(ID: " (capture (some :d)) ")") :price-rule (sequence "$" (capture (some (choice :d "."))))
# La regola principale scorre il testo cercando le nostre regole :main (any (choice :id-rule :price-rule 1))}))
# Esegui la grammatica sul testo(def results (peg/match product-grammar text))
(if results (do (def id (get results 0)) (def price (get results 1)) (g.log (string "ID trovato: " id ", prezzo: " price))))Perché le PEG sono migliori per dati web:
Sezione intitolata “Perché le PEG sono migliori per dati web:”- Leggibilità: le regole hanno un nome (
:id-rule,:price-rule) e possono richiamarsi a vicenda. Non devi decifrare una stringa regex di 50 caratteri. - Composizione: puoi costruire parser complessi combinando regole più piccole e testate.
- Assenza di ambiguità: a differenza delle regex, le PEG non fanno backtracking nello stesso modo imprevedibile. Corrispondono esattamente a ciò che definisci, rendendo le prestazioni prevedibili.
- Strutture dati: il modulo
pegdi Janet può costruire strutture dati complesse (array, dizionari) direttamente dalla fase di parsing, invece di restituire solo stringhe.
Cosa e come scegliere?
Sezione intitolata “Cosa e come scegliere?”- Usa JavaScript/Lua (regex) per validazioni semplici, per esempio “questa stringa sembra un indirizzo email?”.
- Usa Janet (PEG) quando devi estrarre più elementi correlati da un blocco di testo non strutturato, oppure quando la formattazione del sito di destinazione è molto variabile.