Je développe actuellement un petit outil qui permet de traiter des mails en c# .NET avec la bibliothèque WebService.
Je dois récupérer des informations dans ce mail et pour cela j'utilise les class Regex et Match.
Cependant, parfois ma "requête" Regex.Match("Texte dans lequel chercher des informations") prend beaucoup de temps avant de trouver ce que je souhaite dans le texte. Cela est surement dû à la tête de mon Regex qui ressemble à : (([A-Z]{2,15})(((.*)(\s)){1,5}((.*né)|(.*Né)))).
En gros, pour vous expliquer mon raisonnement de débutant sur les Regex : je cherche 1 à 5 mots (écrits en majuscule et ne faisant pas plus de 15 caractères) qui sont suivi du mots "né" ou "Né".
Après cela, j'utilise à nouveau un Regex sur le Match qui vient potentiellement de fonctionner pour récupérer que les "mots" sans le "né" ou "Né".
Donc je pense qu'il y a déjà 2 problèmes : 1) La forme de mon Regex n'est pas quelque chose de très élaborée et 2) Je ne sais pas si utiliser un Regex à la suite de l'autre simplement pour récupérer une partie d'un texte qui se trouve avant un certain mot (comme "né" ou "Né") est vraiment génial...
Mais ma question est la suivante : Existe il un moyen de dire "Si tu prends trop de temps de chercher à Matcher, alors tu t'arrêtes et tu continues comme si tu n'avait rien trouvé" ?
Voici un exemple de code qui vous aidera peut-être :
private string ExempleCode(string texte_Dans_Lequel_Chercher_Information)
{
Regex regex_Nom_Prenom = new Regex(@"(([A-Z]{2,15})(((.*)(\s)){1,5}((.*né)|(.*Né))))");
Match match_Nom_Prenom = regex_Nom_Prenom.Match(texte_Dans_Lequel_Chercher_Information); // A ce niveau là le programme peut être "bloqué" pendent plusieurs minutes
if (match_Nom_Prenom.Success)
{
Regex regex_Nom_Prenom_Suite = new Regex(@"((([A-Z]{2,15})((\s)|(-)|()){1,2}){1,5})", RegexOptions.IgnoreCase);
Match match_Nom_Prenom_Suite = regex_Nom_Prenom_Suite.Match(Convert.ToString(match_Nom_Prenom));
if (match_Nom_Prenom_Suite.Success)
{
return Convert.ToString(match_Nom_Prenom_Suite);
}
throw new ExceptionAbsenceInformationImportante("NOM ET PRENOM");
}
throw new ExceptionAbsenceInformationImportante("NOM ET PRENOM");
}
Est-ce que tu as un extrait de texte sur lequel tester la regex ? D'ailleurs tu peux t'aider à créer une regex avec certains sites comme regex101 qui détaillent le comportement de la regex écrite, par exemple ta regex sur un truc que j'ai écrit au pif : https://regex101.com/r/PTcIDY/1
Est-ce que tu es certain que la perte de temps vient de l'exécution de la regex ? Sur quelle taille de texte tu fais la recherche ?
Je suis pas un expert en regex, loin de là, mais je pense que tu as beaucoup trop de parenthèses.
Si tu ne veux pas capturer les deux derniers caractères à matcher alors ne les capture pas (pas de parentèse, enfin là tu es obligé puisque tu as un "ou" mais je pense qu'il y un autre moyen).
Je pense que tu match trop de caractères avec le ".*".
Tu devrais avoir l'explication sur regex101 mais je redétaille ici :
[A-Z]{2,15}\s{1,5} : match entre 2 et 15 lettres majuscules suivies d'entre 1 et 5 espaces (avec toutes les possibilités différentes d'afficher un espace à l'écran) ;
(?>[A-Z]{2,15}\s{1,5}) : crée un groupe non capturant, les parenthèses permettent de grouper mais aussi de capturer, donc si on veut grouper sans capturer il faut ajouter "?>" après la parenthèse ouvrante ;
((?>[A-Z]{2,15}\s{1,5}){1,5}) : j'ai crée juste avant un groupe non capturant qui match un mot en majuscules (en gros), donc maintenant je précise que je veux en trouver entre 1 et 5 (le {1,5} avant la dernière parenthèse) et capturer le tout (les parenthèses qui englobent le tout) ;
((?>[A-Z]{2,15}\s{1,5}){1,5})[nN]é : maintenant j'ai réussi à capturer les mots en majuscule, je précise ce qu'il doit avoir après, "né" ou "Né", je trouve que c'est plus élégant d'utiliser "[nN]é" pour dire ça, en effet "[nN]" va matcher une seule fois sur "n" ou "N" (les crochets permettent de définir des listes de caractères à matcher).
Alors tout d'abord merci pour ta réponse et désolé de revenir que maintenant sur le sujet..
Pour ma part j'utilise : https://regexr.com/ mais en effet ce dernier ne semble pas prendre en compte le caractère "?"... Je préfère utiliser celui ci justement car https://regex101.com m'indique parfois que mon regex fonctionne et match avec une partie de mon texte alors que dans mon code en c# ce dernier ne fonctionne pas...
Je ne souhaitais pas divulguer le type de texte où je fais ma recherche pour des raisons de confidentialités.. mais j'ai donc modifié le texte avec l'aide de ma superbe imagination et d'un petit article wikipédia (Peu importe, le but étant de vous donner une idée de la forme du texte).
Donc voici le texte dans lequel j'aimerais (au moins) récupérer le nom et prénom, soit ici "ESSAI OPENCLASSROOMS".
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style><!--
..Normal{text-indent:0.00in;text-align:left;vertical-align:top;font-family:'Calibri';font-size:11.00pt;margin:0.00in;}
..Default Paragraph Font{text-indent:0.00in;text-align:left;vertical-align:top;font-size:11.00pt;margin:0.00in;}
--></style>
</head>
<body>
<div> </div>
<div><font size="2" color="red">Ceci est un texte modifié par moi même</font></div>
<div> </div>
<div><font size="3">Hello,</font></div>
<div> </div>
<div><font size="3">Vous trouverez ce qu'il vous faut en pièce jointe
</font><font size="3" color="black">:</font></div>
<div> </div>
<div><font size="3" color="black">OPENCLASSROOMS ESSAI </font></div>
<div><font size="3" color="black">né(e) le 01/01/1966 </font></div>
<div><font size="3" color="black">actuellement étudiant en informatique dans le service DEVELOPPEMENT
</font></div>
<div> </div>
<div><font size="3" color="black">Son N° : 112233445566778</font></div>
<div> </div>
<div><font size="3" color="black">Merci</font></div>
<div> </div>
<div><font size="3" color="black">NOM PRENOM </font></div>
<div> </div>
<div> </div>
<div> </div>
<tbody>
<tr valign="top">
<td style="text-indent:0.00in;margin-left:0.00in;margin-right:0.00in;width:33%;">
</td>
<td style="text-indent:0.00in;text-align:center;margin-left:0.00in;margin-right:0.00in;width:33%;">
</td>
<td style="text-indent:0.00in;margin-left:0.00in;margin-right:0.00in;width:33%;">
</td>
</tr>
</tbody>
</table>
</body>
</html>
Voici maintenant le texte où mon programme tourne pendant plusieurs minutes (toujours modifié à l'aide de mon originalité) :
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
Bonjour, Voici un texte test de Mr ESSAI Openclassrooms, né le 01 01 1966. Très cordialement. Prenom NOM Chauffeur, je suis du texte que j'ai enlevé mais ce n'est pas important Mr BLUE et Mr GREEN Etablissement Tél : 00 11 22 33 44 Fax : 55 66 77 88 99
Le vin est une boisson alcoolisée obtenue par la fermentation du raisin, fruit de la vigne viticole.
La transformation du raisin en vin est appelée la vinification.
L'étude du vin est l'œnologie. La grande variété de vins existant au monde s'explique par les différences de terroirs, de cépages, de modes de vinification ou de types d'élevage.
Ainsi ils peuvent donner des vins rouges, rosés ou blancs, mais aussi des vins avec un taux de sucre résiduel variant (secs ou doux), ou une effervescence variante (tranquilles ou effervescents). La viticulture a colonisé une vaste partie du monde et de très nombreux pays sont producteurs de vin.
Selon sa définition légale en Europe1, le vin est le produit obtenu exclusivement par la fermentation alcoolique, totale ou partielle, de raisins frais, foulés ou non, ou de moûts de raisins, les boissons alcoolisées aromatisées à base de raisins ne pouvant pas comporter cette appellationN 1.
Son titre alcoolique ne peut être inférieur à 8,5 % en volume.
Selon sa définition légale en Europe1, le vin est le produit obtenu exclusivement par la fermentation alcoolique, totale ou partielle, de raisins frais, foulés ou non, ou de moûts de raisins, les boissons alcoolisées aromatisées à base de raisins ne pouvant pas comporter cette appellationN 1.
Son titre alcoolique ne peut être inférieur à 8,5 % en volume.
</body>
</html>
Mon but pour ce type de texte n'étant pas de matcher le nom et prénom mais simplement de ne pas rester "bloqué" plusieurs minutes, j'ai essayé ta regex (qui est bien plus jolie que la mienne) cette dernière ne fonctionne pas. J'ai alors essayé d'améliorer la mienne en la remplaçant par : @"(([A-Z]{2,15}\s{0,2}){1,5}((.*)|(\s)){1,5}[nN][ée])". Maintenant, cela fonctionne !! Mon programme ne reste plus bloqué... jusqu'à la prochaine fois où cela recommencera peut-être... Car en effet, ma regex utilise toujours le ".*" qui n'est pas forcément génial.
Ainsi, je vais marquer le sujet comme "résolu" mais je pensais résoudre (si c'est possible) mon problème de la manière suivant :
Imaginons une boucle infinie :
for (int i = 0; i > -5; i++)
{
// Je veux sortir si je tourne dans cette boucle depuis plus de 5 secondes !!!
}
Est il possible de dire à mon programme "Bon la ca fait plus de 5 secondes que tu es bloqué dans cette boucle for, alors sort de là stp", et si oui comment peut on faire ??
Le problème est plus compliqué que ce que j'avais compris.
En général si tu veux extraire de l'information d'un texte style html/xml il vaut mieux utiliser un parser qui sert à ça.
Mais là apparemment t'as aucun identificateur permettant de désigner du texte comme étant un nom.
Si j'ai bien compris tu as décidé de considérer que ce serait toujours écrit comme "NOM Prénom né le". Sauf que c'est pas écrit directement comme ça à cause des balises, et t'as réglé le problème en mettant "(.*)" (au passage t'es pas obligé de mettre des parenthèses partout, elles ne servent qu'à capturer, le match sera fera tout le temps) et c'est ça qui met le moteur regex à genou, il y a trop de backtracking, regex101 m'a renvoyé cette erreur avec ta dernière regex sur ton premier exemple :
Catastrophic backtracking has been detected and the execution of your expression has been halted. To find out more what this is, please read the following article: Runaway Regular Expressions (http://www.regular-expressions.info/catastrophic.html)
I recommend you launch the debugger in the menu to the left and analyze the data to find out the cause.
Au passage, en me renseignant un peu plus il apparaît que .NET utilise son propre moteur regex, donc il vaudrait mieux les tester sur ce site : http://regexstorm.net/tester
Du coup pour ton premier exemple je ne sais pas trop ce qui serait la meilleure solution, peut-être en enlevant d'abord toutes les balises html puis en appliquant la regex sur le texte brute ça devrait mieux aller, mais ça me paraît foireux quand même.
Pour ton deuxième exemplace ça devrait être plus facile puisque tout le texte est dans une balise body, par contre il y a une virgule à prendre en compte dans la regex et ça donne ça en repartant de la mienne : "((?>[a-zA-Z]{2,15}\s{0,5}){1,5}),\s[nN]é" (testée avec le deuxième texte).
Du coup ça capture aussi "test de Mr" parce qu'on demande entre 1 et 5 mots avant la virgule, donc si c'est pour capturer un nom c'est pas encore ça.
Mais ça doit pas être facile non plus parce qu'il peut y avoir plusieurs prénoms, des noms composés (séparés par un espace, un tiret, une apostrophe ou autre). A la limite on pourrait faire un regex qui capture tout ce qu'il y a entre "Mr" (ou "Mme" ou "Mlle") et ", né".
EDIT : pour le site que tu utilisais, il a l'air d'être configuré par défaut pour utiliser le moteur regex javascript qui ne support pas "?>", en le passant en mode PCRE (bouton en haut à droite) ça marche. Mais de toute manière c'est pas non plus le moteur utilisé par .NET donc autant utiliser l'autre lien que j'ai donné plus haut.
- Edité par Stormweaker 4 juin 2019 à 15:22:04
Match Regex Time trop long
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
LeCodeurFou
LeCodeurFou