Salut,
A vrai dire, les expressions régulières ne te seront pas d'un très grand secours pour résoudre ton problème. Je m'explique:
Une expression régulière va parcourir une "chaine de caractères d'origine" à la recherche d'un patron, représenté sous la forme d'une chaine de caractères, qui permettra à l'expression régulière d'extraire une "sous chaine de caractères" de la "chaine d'origne" si le patron recherché est trouvé.
C'est certes très pratique, mais... cela ne remplit certainement pas l'ensemble de nos besoins, car ceux-ci vont "un cran plus loin" en nécessitant de convertir les chaines de caractères qui représentent des nombres en valeurs numériques.
Attention, je ne dis absolument pas que l'on ne peut en aucun cas avoir recours aux expressions régulières. Je dis juste que c'est peut être se faire "beaucoup de mal pour rien", car les moyens dont on dispose pour convertir une chaine de caractères en valeur numérique ne nécessitent absolument pas que la chaine convertie ne soit composée que du nombre à convertir.
De manière générale, pour extraire les valeurs numériques d'une chaine de caractères en C++, tu dois utiliser les fonctions std::sto* (std::stoi et autres pour les entiers, std::stof, std::stod, et std::stold pour les réels).
Le deuxième paramètre (le premier qui soit optionnel) nous permet de fournir un pointeur sur un entier qui correspondra à la position du premier caractère de la chaine de caractères qui "ne fait clairement pas partie du nombre".
Par contre, il faudra jouer avec les "sous-chaines de caractères" afin de pouvoir récupérer les différents opérateurs et, au delà, l'expression complète que l'on souhaite évaluer.
Par contre, il va aussi falloir prendre en compte le fait que la partie décimale d'un nombre en informatique est représentée par le point "." et non par la virgule ","
Ainsi, si on veut traiter une chaine de caractères (que je vais utiliser tout au long de cette explication) qui prend la forme de " std::string str = "9,42+308,7-41+36*234,56/546+7.56*769,3";, les deux premières choses que nous voudrons faire sont:
- effectuer une "copie de travail" de la chaine, afin de ne pas aller modifier la chaine "d'origine"
- remplacer toutes les virgules qui apparaissent par des points, histoire que nos fonctions de conversion y "retrouvent leur jeunes".
La première étape est toute simple, car il nous suffira d'une ligne proche de
pour avoir une variable nommée copy qui est la copie conforme de la chaine de caractères str.
La deuxième étape n'est a priori pas beaucoup plus compliquée, car nous disposons d'une fonction d'algorithme nommé std::replace_if capable de le faire pour nous (il faut juste penser à inclure le fichier d'en-tête <algorithm>). Une ligne proche de
std::replace_if(copy.begin(), copy.end(), [](char c){return c==',';},'.');
devrait faire l'affaire
Je sais, elle a l'air compliquée comme cela, mais elle en fait, elle est toute simple et parfaitement logique... si tu ne la comprends pas, n'hésite pas à me le dire, je t'expliquerai le tout au besoin 
Bien, maintenant que nous avons la certitude que la chaine de caractères (copy) pourra être traitée correctement avec la fonction std::stof, il est peut être utile de prendre trente secondes pour réfléchir à notre situation actuelle et au résultat que l'on souhaite obtenir...
Notre situation actuelle est que nous sommes désormais face à une chaine de caractères dont on peut clairement dire qu'il s'agit "d'une expression mathématique" (complexe).
Notre objectif de départ étant de récupérer les différentes valeurs numériques que cette expression contient, ainsi que ... les opérateurs mathématiques qui séparent ces différentes valeurs (ce sera plus facile, semblet-t-il, pour atteindre l'objectif final
).
L'objectif final étant de pouvoir évaluer le résultat de cette expression une fois que toutes les opérations auront été effectuées. Accessoirement, s'il y avait moyen de respecter les règles de priorités pour les différents opérateurs, ce serait franchement pas mal 
Tiens, au fait... Je viens d'introduire quelques notions sympa ici, dont la notion d'"opérateurs mathématiques". Comme ces opérateurs seront essentiels au calcul du résultat final, nous serions peut être bien inspirés d'introduire cette notion dans notre "DSL" (acronyme de Domain Specific Language ou, si tu préfères, notre langage spécifique au domaine de notre projet).
Le plus simple serait sans doute de créer une énumération reprenant les quatre opérations de base et qui serait proche
1 2 3 4 5 6 7 8
|
enum MathOperator{
plus,
minus,
multiply,
divide,
max
}; |
La valeur "max" n'est présente ici que pour une question de facilité, car elle nous permettra par la suite des choses sympa ... ou non 
Et, bien sur, on pourrait fournir une fonction qui fournisse la valeur énumérée correspondant au symbole représenté par le caractère en question:
1 2 3 4 5 6 7 8 9 10
| constexpr MathOperator mathFromChar(char c){
switch c{
case '+' : return plus;
case '-' : return minus;
case '*' : return multiply;
case '/' : return divide;
default : assert(false && You should never come here");
}
return max;
} |
Cette fonction est déclarée comme étant constexpr uniquement parce que cela permettra au compilateur de faire quelques optimisations supplémentaires 
Maintenant que nous avons une fonction pour extraire un float (je parle bien sur de std::stof) et une autre fonction pour récupérer le type d'opérateur mathématique utilisé dans le cadre de "l'expression mathématique dont on veut calculer le résultat, ben ... YAPUKA ... mettre tout cela en musique 
Pour se faire, nous aurons encore besoin de deux variables particulières:- un float, d'abord, pour pouvoir extraire les réels représentés par la chaine de caractères et
- un size_t ensuite, pour savoir la position du "premier caractère n'ayant pas été utilsé par la fonction.
le float peut être déclaré au moment où l'on récupère le résultat de std::stof, par contre le size_t devra être déclaré avant (car on doit en prendre l'adresse pour la transmettre à stof...).
Cela pourrait prendre une forme proche de
1 2 3
|
size_t position{0};
float extracted = std::stof(copy, &position); |
Nous pouvons "assez facilement" utiliser la nouvelle valeur de position pour récupérer l'opérateur mathémathique sous une forme proche de
MathOperator oper = mathFromChar(copy[position]);
Bien sur, nous ne devons donc pas oublier que le premier caractère qui nous intéresse se trouve désormais à position +1, mais il est désormais temps de supprimer "tout ce qui a déjà été traité" de la chaine:
copy = copy.substr(position + 1);
Nous sommes désormais rendus au point où - nous avons extrait la première valeur numérique de la chaine de caractères
- nous avons extrait le premier opérateur mathématique de la chaine de caractères
- nous avons supprimé de la chaine de caractères tous les caractères qui ont déjà été utilisés lors des deux extractions sus-citées.
Ce qu'il faut désormais, c'est "continuer sur cette lancée" afin de parcourir toute la chaine de caractères... Et ca, je vais te laisser faire, autrement, cela n'aurait absolument aucun intérêt 
Dans l'idéal, il faudrait trouver le moyen de stocker toutes les informations obtenues, histoire que l'on puisse les manipuler "à notre aise" ... après avoir parcouru toute la chaine de caractères 
Fais attention au fait qu'il y a peut être une petite astuce à la fin de la chaine de caractères, étant donné qu'elle est censée se cloturer par ... une valeur numérique
Une fois que nous aurons parcouru l'ensemble de la chaine de caractères, il faudra trouver le moyen de "recréer" l'expression mathématique qu'elle représentait de manière à pouvoir en calculer le résultat final.
Soit toujours bien attentif au fait que la multiplication et la division ont priorité sur l'addition lorsque tu évalue le résultat final.
Une fois que tu en sera rendu là, nous pourrons éventuellement améliorer le tout en ajoutant le support d'espaces "surnuméraires" (par exemple avant et après un opérateur mathématique), mais ... à chaque jour suffit sa peine, n'est ce pas?
Partager