En Perl, l'analyse lexicale (lexing) et le parsing des chaînes sont souvent utilisés pour traiter des modèles textuels complexes. De nombreuses tâches (par exemple, le parsing des parenthèses imbriquées, des guillemets, des requêtes SQL) ne peuvent pas être réalisées avec de simples expressions régulières en raison de leur nature linéaire. Dans de tels cas, on utilise des modules qui implémentent les bases du parsing — par exemple, Text::Balanced.
Text::Balanced est conçu pour extraire des parenthèses équilibrées, des guillemets appariés et d'autres structures imbriquées. Il fonctionne là où les expressions régulières échouent (par exemple, le parsing des constructions imbriquées { ... { ... } ... }). Parmi les alternatives, on trouve les modules Parse::RecDescent, du code maison basé sur une pile et la récursion, ainsi que des parsers externes.
Exemple d'utilisation de Text::Balanced et comparaison avec regexp :
use Text::Balanced 'extract_bracketed'; my $data = 'foo({bar(baz)},qux)'; my ($extracted, $remainder) = extract_bracketed($data, '()'); print $extracted; # Affichera : ({bar(baz)},qux)
Une expression régulière ne pourra pas correctement analyser des parenthèses imbriquées :
data =~ /(\(.*\))/; # ne capturera que la première et la dernière parenthèse, en ignorant l'imbrication
Est-il possible d'identifier correctement des parenthèses équilibrées dans des chaînes de profondeur variable à l'aide d'expressions régulières Perl classiques ?
Réponse : Non, les expressions régulières Perl ne peuvent pas traiter des modèles récursifs (sauf PCRE, mais pas le Perl standard). Pour une tâche similaire, il faut utiliser un parser (Text::Balanced, parser basé sur une pile, Parse::RecDescent). Tenter de résoudre la tâche avec une expression régulière entraînera des erreurs en cas de syntaxe imbriquée.
Exemple :
# NE fonctionnera PAS pour foo({bar(baz)},qux) my ($br) = $data =~ /(\(.*\))/;
Histoire
Dans le projet, il y a eu des tentatives de parser du JSON manuellement avec des expressions régulières. Le développeur pensait que l'expression
(\{.*\})trouverait le fragment nécessaire, mais avec de vraies données comportant des objets imbriqués, le parser choisissait une mauvaise limite, ce qui entraînait une perte de données et des erreurs dans le traitement des paramètres d'entrée.
Histoire
Dans le journal XML des événements, il fallait extraire le contenu d'une balise avec des balises potentiellement imbriquées. Une compréhension insuffisante des principes de la récursion en lexing a conduit à un parsing incorrect des événements et à l'ignorance des éléments imbriqués, entraînant une perte d'informations.
Histoire
Erreur lors du parsing d'une requête SQL par un script de migration : des cas exceptionnels comme les sous-requêtes entre parenthèses n'ont pas pu être analysés. Les expressions régulières "cassaient" déjà au niveau de simples chaînes imbriquées, ce qui a conduit à la formation de requêtes SQL incorrectes.