02/09/2015
Paradoxalement c'est en C++ que les expressions régulières sont les plus simples à employer. Il suffit de connaître la syntaxe ECMAScript et les trois méthodes regex_match, regex_search et regex_replace. Accessoirement nous utiliserons une nouveauté de C++11 : for x: conteneur
Le site cplusplus.com est certainement le plus clair et le plus documenté.
C'est la syntaxe utilisé par défaut par C++. La syntaxe rappelle celle bash.
Les caractères spéciaux sont:
^ : Début de la ligne ou de la chaîne $ : Fin de ligne ou de chaîne \ : caractère d'échappement des caractères spéciaux . : n'importe quel caractère * : 0 ou plusieurs fois + : 1 fois ou plus ? : 0 ou une fois ( ) : groupe, on y fait appel avec $1, $2 ou m[1], m[2] etc. [ ] : ensemble | : alternative Exemples :
$1.# commentaire"+ Ligne n° 1".lien. zob est inconvenant, mais convient quand même.On souhaite reconnaitre une url http ou ftp.
L'expression régulière est "(http|ftp)://([^. ]+)\\.([^. ]+)\\.(.+)"
Elle se décompose ainsi :
(ftp|http) : groupe, concorde avec 'http' ou 'ftp'
:// : tel quel, ne constitue pas un groupe
([^. ]+) : groupe, correspond à un ou plusieurs caractères ni point ni espace. Remarque : entre [] il n'est pas nécessaire d'échapper le point
\\. : un point, ne constitue pas un groupe
([^. ]+) : déjà rencontrée. Dans [^. ] le circonflexe signifie non et pas début.
\\. : encore un point
(.+) : groupe, le reste de l'expression
Finalement la regex est "(http|ftp)://([^.]+)\\.([^.]+)\\.(.+)"
La syntaxe simple est regex_match(s, re) mais on emploie plus souvent la syntaxe regex(s, m, re) où s est la chaîne dans laquelle on cherche, re l'expression régulière et m de type smatch (ou cmatch) permet de récupérer les correspondances. Dans l'exemple ci-dessus, s'il y a correspondance, on aura :
m[0] : la chaîne entière
m[1] : ftp ou http
m[2] : vraisemblablement ftp ou www ou un sous domaine
m[3] : le nom du site
m[4] : le suffixe com fr net etc.
//compile: !g++ -std=c++11 -Wfatal-errors -o regex_match regex_match.cpp#include <iostream> // pour cout#include <string> // pour string#include <regex> // but de l'articleusing namespace std;//----------------------------------------------------int main(){string s = "ftp://ftp.arad.free.fr";//string s = "http://www.arad.free.fr";smatch m; // string matchescout << "matches : ";regex re("(http|ftp)://([^.]+)\\.([^.]+)\\.(.+)");// The entiere string s must match the régular expressionif(regex_match(s, m, re))for(unsigned c = 0; c < m.size(); c++)cout << "m[" << c << "] = " << m[c] << endl;cout << endl;return 0;}
Source : regex_match.cpp
Exemple permettant de reconnaitre la notation utilisée par lilypond pour représenter une note :
regex re("([a-g](?:es)?(?:is)?)([',]{0,3})([0-9]{0,3})([.]?)");
Une note est composée d'une lettre [a-g] suivie de 'is' ou 'es' suivie d'une apostrophe ou d'une virgule, suivie d'un nombre, suivi d'un point. Sauf la lettre de départ, tout le reste est facultatif.
La différence avec match, est que search cherche à l'intérieur de la cible. Dans l'exemple ci-dessous on trouve deux occurences du patron recherché.
string = " { ais4 c. }"smatch m;regex_search(s, m, ex)
Les méthodes prefix() et suffix() permettent en plus connaître la chaîne qui précède la coïncidence et celle qui la suit.
A la fin du while, on exploite la méthode suffix() pour poursuivre la recherche.
//compile: !g++ -std=c++11 -Wfatal-errors -o regex_match regex_match.cpp#include <iostream> // pour cout#include <string> // pour string#include <regex> // but de l'articleusing namespace std;//----------------------------------------------------int main(){string s = "Le site http://www.arad.free.fr a été rédigé avec Qlam : http://www.arad.free.fr/qlam;";//string s = "http://www.arad.free.fr";smatch m; // string matchesregex re("(http|ftp)://([^.]+)\\.([^.]+)\\.([^. ]+)");// The entiere string s must match the régular expressionwhile(regex_search(s, m, re)) {cout << "Prefix: " << m.prefix().str() << endl;for(unsigned c = 0; c < m.size(); c++)cout << "m[" << c << "] = " << m[c] << endl;cout << "Suffix: " << m.suffix().str() << endl;s = m.suffix().str();}return 0;}
Source : regex_search.cpp.
#include <iostream>#include <string>#include <regex>#include <map>using namespace std;/*map char html_entitiefirst : char to replacesecond : string replacement*/map <string, string> dict = {{"<", "<"}, {">", ">"},{"\\[", "["}, {"\\]", "]"},{"/", ""}, {"#", "#"},{"\\*", ""}, {"_", "_"}}; // dict/*syntax: s2 = dict_replace(s1);replace in s1 <, >, [, ], /, * _ by html_dict_replace*/string dict_replace(string s){for(auto& x: dict) { // for each x in dicts = regex_replace(s, regex(x.first), x.second);}return s;}//----------------------------------------------------int main(){string s;do {cin >> s;if(s == "bye") break;cout << s << " -> " << dict_replace(s) <<endl;} while(true);return 0;}
Fchier source : regex_replace.cpp
map <string, string> dict crée un conteneur associatif (comme le dict de python). On peut utiliser .first et .second pour la clef et la valeur. for(auto x: dict) signifie pour tout x dans dict. Avec auto, on est dispensé d'indiquer le type. C'est utile dans certains cas où le type est déterminé par le compilateur. regex_replace prend trois paratmètres : la cible, la regex et le remplaçant.