Aller au contenu

Extraction de texte (PEG ou regex)

Lorsque vous automatisez des navigateurs, vous rencontrez souvent des données « sales » : texte formaté de façon incohérente, contenant des fautes ou mélangeant plusieurs types d’informations dans une même chaîne.

JavaScript et Lua s’appuient sur les expressions régulières (regex) pour ce travail, tandis que le moteur Janet de Guida inclut un moteur Parsing Expression Grammar (PEG) intégré. Les PEG sont une alternative puissante aux regex qui rend l’extraction de texte complexe plus facile à lire, écrire et maintenir.

Les regex sont excellentes pour les motifs simples, mais deviennent vite illisibles lorsqu’il faut gérer des structures complexes ou imbriquées.

Imaginez l’extraction du prix et de l’ID d’un produit depuis une chaîne désordonnée comme "Item: SuperWidget (ID: 98765) - Only $49.99 today!".

const text = "Item: SuperWidget (ID: 98765) - Only $49.99 today!";
// Regex is dense and relies on capturing groups that are extracted by index
const regex = /\\(ID:\\s*(\\d+)\\).*?\\$([0-9.]+)/;
const match = text.match(regex);
if (match) {
const id = match[1];
const price = match[2];
g.log(`Found ID: ${id}, Price: ${price}`);
}

Cela fonctionne, mais la regex reste fragile. Si le format change légèrement, elle échoue, et la modifier demande de la gymnastique mentale.

Le module peg de Janet permet de construire des parseurs par composition. Au lieu d’une énorme chaîne cryptique, vous définissez une grammaire comme dictionnaire de règles lisibles.

(def text "Item: SuperWidget (ID: 98765) - Only $49.99 today!")
# Define a clean, compositional grammar
(def product-grammar
(peg/compile
~{:id-rule (sequence "(ID: " (capture (some :d)) ")")
:price-rule (sequence "$" (capture (some (choice :d "."))))
# The main rule scans through the text looking for our rules
:main (any (choice
:id-rule
:price-rule
1))}))
# Run the grammar against the text
(def results (peg/match product-grammar text))
(if results
(do
(def id (get results 0))
(def price (get results 1))
(g.log (string "Found ID: " id ", Price: " price))))

Pourquoi les PEG sont utiles pour les données web

Section intitulée « Pourquoi les PEG sont utiles pour les données web »
  1. Lisibilité : les règles sont nommées (:id-rule, :price-rule) et peuvent se référencer entre elles. Vous n’avez pas à décoder une regex de 50 caractères.
  2. Composition : vous pouvez construire des parseurs complexes en combinant de petites règles testées.
  3. Absence d’ambiguïté : contrairement aux regex, les PEG ne backtrackent pas de la même façon imprévisible. Ils correspondent exactement à ce que vous leur demandez, avec des performances plus prévisibles.
  4. Structures de données : le module peg de Janet peut construire des structures complexes, tableaux ou dictionnaires, directement depuis l’étape de parsing, au lieu de renvoyer seulement des chaînes plates.
  • Utilisez JavaScript/Lua avec regex pour les validations simples, par exemple vérifier si une chaîne ressemble à une adresse e-mail.
  • Utilisez Janet avec PEG lorsque vous devez extraire plusieurs morceaux de données liés depuis un bloc de texte désordonné, ou lorsque le format du site cible varie beaucoup.