Les expressions régulières gourmandes & non gourmandes en C++
Les expressions régulières sont essentielles pour extraire des informations dans du texte structuré, notamment en HTML. Cependant, la manière dont elles capturent les données peut varier selon qu'elles sont gourmandes (greedy) ou non gourmandes (non-greedy). Dans cet article, nous allons explorer ces concepts en C++ et présenter deux solutions valides pour extraire des liens (étiquettes <a href>
), tout en discutant des cas d'utilisation et de la maintenance du programme.
1. Qu'est-ce qu'une expression régulière gourmande ?
Une expression régulière gourmande (greedy regex) tente de capturer le plus de texte possible. Cela peut poser problème lorsque nous cherchons à extraire une partie bien définie d'un texte, comme une URL contenue dans une balise HTML.
Exemple de problème avec une regex gourmande
#include <iostream>
#include <fstream>
#include <string>
#include <regex>
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <html_file>\n";
return 1;
}
std::ifstream file(argv[1]);
if (!file) {
std::cerr << "Erreur : impossible d'ouvrir le fichier.\n";
return 1;
}
std::string html((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close();
std::regex greedy_regex(R"(href="http.*")"); // Expression régulière gourmande
std::smatch match;
auto begin = std::sregex_iterator(html.begin(), html.end(), greedy_regex);
auto end = std::sregex_iterator();
for (auto i = begin; i != end; ++i) {
std::cout << (*i).str() << std::endl;
}
return 0;
}
Problème : Cette regex capture tout le texte entre la première occurrence de href="http
et la dernière double quote "
, ce qui inclut parfois des données non souhaitées.
2. Solutions pour un résultat plus précis
Solution 1 : Utilisation d'une regex non gourmande
Une regex non gourmande (non-greedy) capture le moins de texte possible en s'arrétant à la première occurrence de l'élément de fin.
std::regex non_greedy_regex(R"(href="http.*?")");
Cela permet d'obtenir uniquement les URL sans capturer du texte indésiré.
Solution 2 : Empêcher les guillemets intérieurs
Une autre approche consiste à interdire les guillemets intérieurs avec [^\"]+
, ce qui garantit une extraction propre.
std::regex precise_regex(R"(href="http[^"]+")");
Cela signifie :
http[^"]+
: Capture un lien HTTP sans inclure les"
internes.
3. Cas d'utilisation des regex gourmandes et non gourmandes
Quand utiliser une regex gourmande ?
Lorsqu'on souhaite capturer une structure englobante, comme un bloc de texte entre deux balises HTML (
<div>...</div>
).Extraction de logs ou de configurations avec des blocs bien définis.
Quand utiliser une regex non gourmande ?
Extraction de petits éléments comme des URL ou des mots-clés.
* Extraction des citations imbriquées
4. Amélioration du programme et maintenance
Pour éviter les doublons et enregistrer les liens extraits dans un fichier, nous pouvons améliorer notre programme comme suit :
#include <iostream>
#include <fstream>
#include <string>
#include <regex>
#include <set>
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <html_file>\n";
return 1;
}
std::ifstream file(argv[1]);
if (!file) {
std::cerr << "Erreur : impossible d'ouvrir le fichier.\n";
return 1;
}
std::string html((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close();
std::regex href_regex(R"(href="(https?://[^"]+)")");
std::sregex_iterator begin(html.begin(), html.end(), href_regex);
std::sregex_iterator end;
std::set<std::string> links;
for (auto i = begin; i != end; ++i) {
links.insert((*i)[1]); // Stocke dans un ensemble pour éviter les doublons
}
std::ofstream output("extracted_links.txt");
for (const auto& link : links) {
output << link << std::endl;
}
std::cout << "Extraction terminée. Liens enregistrés dans extracted_links.txt\n";
return 0;
}
5. Conclusion
Les expressions régulières jouent un rôle essentiel dans l'extraction de texte, mais leur bon usage est crucial (Web server administration, SEO..). Les regex gourmandes capturent le maximum de texte, tandis que les non-gourmandes limitent la capture au strict nécessaire. Dans la plupart des cas d'extraction HTML, il est préférable d'utiliser des regex non gourmandes ou des patrons bien définis. Une bonne conception permet non seulement d'optimiser la performance mais aussi d'assurer la maintenabilité du code.
Comments
Post a Comment