MATCHESMASK ET LES EXPRESSIONS RÉGULIÈRES.

florenth - 2 août 2007 à 18:57
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 - 7 août 2007 à 18:09
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/43645-matchesmask-et-les-expressions-regulieres

Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
7 août 2007 à 18:09
mon prog doit exister en delphi, .net, etc.

ce genre de choses :
((expr1)|(expr2)
@Delphiprog: Il ne s'agit pas de *froissage* d'esprit, ou de tout autre artefact mais plus d'un débat quand à la meilleure méthode pour effectuer ce genre de recherche.
Dans ce contexte, ta remarque est tout à fait la bienvenue. En plus, les liens que tu cites sont à la fois intéressants et complets.

@Renfield: ton programme a l'air drôlement utile. Seul ennui: c'est du VB ! Comment on fait pour s'en servir ? Tu fournis l'exe mais il manque toujours les ocx pour que ça veuille bien démarrer.

Sinon, toujours pour rester dans le domaine des regexp, on a toujours le même problème : si j'ai ^(expression1|expression2)$, comment je sais laquelle des deux sous-expressions à été matchée ?
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
7 août 2007 à 09:33
ta regexp ne me convient pas tout a fait. Elle décrit :

255
comme étant une IP valide...

de plus, si je testes:
192.168.1.204

le '4' n'est pas dans le match

http://www.vbfrance.com/codes/REGEXP-WORKSHOP_17331.aspx
cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
7 août 2007 à 09:24
Mille excuses à vous deux mais je n'avais pas l'intention de froisser les esprits. Je sais fort bien que Caribensila n'est pas du genre à poster des codes à deux balles. Qu'il me pardonne s'il s'est senti offensé et je lui ferai parvenir une tarte au concombre pour me faire pardonner. :o)
Le message que j'ai voulu faire passer est l'intérêt, sur le long terme, de se pencher sur l'étude des expressions régulières du fait qu'elle sont disponibles dans quasiment tous les langages et presque universelles (différentes normes existent).
Le temps passé à écrire la fonction postée ici aurait été bien moindre avec les expressions régulières.
Le fait d'utiliser telle ou telle bibliothèque importe peu du moment que la bibliothèque en question respecte les normes "industrielles".

@florenth : pour info, voici l'expression que j'utilise pour valider une adresse IP V4 :
^(([01]?\d\d?|2[0-4]\d|25[0-5])\.){3}[01]?\d\d?|2[0-4]\d|25[0-5]$

Ceci démontre, par la même occasion, qu'il n'y a pas qu'une vérité et qu'on peut parvenir au résultat recherché de différentes manières.
Désolé, mais je n'ai pas mis de commentaire dans cette expression régulière.
Pour finir, je suis entièrement d'accord avec vous deux pour dire que la fonction MatchesMask est très largement méconnue et donc, à fortiori, sous utilisée. C'est bien dommage et merci à Caribensila de l'avoir remise au goût du jour.
Au fait Cari, pourquoi MatchesMask pour trouver une IP ?
Je n'y avais pas pensé avant, mais c'est super simple :




Matériel: un TEdit, un TButton et un TMemo
--------------------------------------------------------------------
function ParseString(const S: string; var Position: Integer;
AllowedChars: TSysCharSet): string;
var
Debut: Integer;
begin
Debut := Position;
while (Position <= Length(S)) and (S[Position] in AllowedChars) do
Inc(Position);
Result := Copy(S, Debut, Position - Debut);
end;

type
TIPAddr = array[0..3] of Byte;

function IsValidIP(const S: string; out IPAddr: TIPAddr): Boolean;
var
Num, Position, TempI: Integer;
begin
Result := False;
Position := 1;
for Num := 0 to 3 do
begin
TempI := StrToIntDef(ParseString(S, Position, ['0'..'9']), -1);
if not (TempI in [0..255]) then
Exit;
IpAddr[Num] := TempI;
if (Num <> 3) and (S[Position] <> '.') then
Exit;
Inc(Position);
end;
Result := Position > Length(S);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
IP: TIPAddr;
I: Integer;
begin
if IsValidIP(Edit1.Text, IP) then
begin
Memo1.Clear;
Memo1.Lines.Add('IP Valide');
for I := 0 to 3 do
Memo1.Lines.Add(IntToStr(IP[I]));
end
else
Memo1.Text := 'IP non valide';
end;
--------------------------------------------------------------------

Alors, qu'en penses-tu ?

Et puis dis moi, tu vas pas t'arrêter là maintenant que tu t'y est lancé ! Pour la semaine prochaine, un petit exemple avec une regex, ça te tente pas ?? ;-)

PS: mon exemple n'est pas "gerbant", c'est juste que à part celui qui l'a écrit (donc moi), les autres vont mettre du temps à comprendre le pourquoi du comment.
Quoi que à ce qu'il parait, on peut mettre des commentaires dans les regex...
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
6 août 2007 à 15:39
@Delphiprog

Tu casses pas l'ambiance, t'en mets! lol
Et on a l'habitude et surtout le plaisir de se faire appeler 'Arthur' quand notre cher Delphiprog remet les pendules à l'heure car ce n'est jamais inutile.

D'autant que ce sont tes quelques réponses sur le forum au sujet des expressions régulières qui m'ont donné l'envie de les connaître et l'idée de les présenter aux autres débutants comme moi (y'a pas que des surdoués, ici). Mais je ne voulais pas les rebuter avec une bibliothèque dédiée et tout l'investissement en temps que ça demande. MatchesMask, dans sa simplicité était une bonne introduction j'ai pensé (voir l'exemple gerbant de Florenth avec regex).

De plus, comme le souligne Florenth, ce n'est pas un code d'extraction d'IP que j'ai posté. Tout au plus un code d'extraction de 'trucs qui ressemblent à des IP' (Comment savoir si 123.125.365.325 est une IP valide ou un N° de tél de Papouasie?). Ce n'était qu'un prétexte pour illustrer MatchesMask qui est peu connue. Et si on arrive aux limites de cette fonction, ça aura au moins servi à montrer MatchesMask() et ces limites.

Quant à valider une IPv6, j'y suis arrivé très facilement avec quelques changements triviaux dans les masques et la gestion des doubles-points qui se suivent. Et si j'y arrive, c'est que c'est pas difficile. ;)

On est donc d'accord sur l'intérêt d'étudier les expressions régulières. Mais sans effrayer, en douceur. :)))
Ensuite..? Il y a les bonnes pistes que tu as signalées. Merci à toi et à Flo.
Je trouve ta critique envers ce code un peu dure.
Si le but de cette source est de montrer l'utilité de la fonction MatchesMask() et ses domaines d'application, alors ce but est parfaitement rempli, même si les IPs validées ne sont pas toutes justes (c'est juste une question de pertinence).

Cela dit, je suis d'accord avec toi sur l'utilité des expressions régulières et ce n'est pas pour rien que je les utilise couramment.
Excuse aussi mon doigt d'avoir glissé pour écrire le PCRE et mon cerveau pour n'avoir pas détecté la faute.

D'ailleurs, au passage, pour valider une IP avec une regex, il faut avoir le coeur bien accroché, surtout pour relire ... et pour comprendre !

CIPRegex = '^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})$';
cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
5 août 2007 à 22:59
Que de code pour valider une adresse IP !
De plus, si je n'ai pas lu trop vite le code, une adresse telle que 00.00.00.00 serait valide ?
Quant à valider une adresse IP V6, on en est loin.
Non, sérieusement, la fonction MatchesMask bien que très utile, atteint ses limites dans le cas présent.
Autant se tourner vers une bonne bibliothèque pour Delphi telle que Regexp Studio (libre et gratuite, pourquoi s'en priver ? http://www.regexpstudio.com/).

Florenth : c'est PCRE (Perl Compatible Regular Expressions) et non prce (voir http://en.wikipedia.org/wiki/PCRE)

Désolé d'avoir un peu cassé l'ambiance mais il m'a semblé nécessaire de remettre les choses dans leur contexte.
D'un côté on a une chaine à analyser et de l'autre, une expression régulière. Le moteur se charge alors de vérifier que le pattern est applicable à la chaine et d'en extraire une partie ou toutes les parties.
Dans le code de Caribensila, c'est une fonction dédiée à la vérification qui est codée. C'est peut-être plus performant pour cet usage, mais c'est moins souple et moins réutilisable sur le long terme.
D'où l'intérêt d'apprendre les expressions régulières même si ça parait rebutant au premier abord. Quand on les a manipulé un certain nombre de fois et qu'on pratique plusieurs langages, le savoir devient immédiatement réutilisable et ça, ça n'a pas de prix.

Allez, quelques bonnes pistes :
Quick reference : l'essentiel des regexp en une page
http://www.night-ray.com/regex.pdf
Pour le reste : http://tinyurl.com/2jwkgd

Bon, c'est encore les vacances pour certains. Si vous cherchez de la lecture intéressante, y a qu'à demander.
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
2 août 2007 à 19:40
Merci pour tes remarques toujours aussi pertinentes, Florent :)

- Tu as raison, ça lit bêtement en-dehors de la chaîne. Le pire c'est que je m'en étais aperçu et que j'avais corrigé. Mais j'ai dû oublier de sauvegarder le changement ( quel con ce Cari! ).

- "Str(GetTickCount-Deb,S);" c'est juste pour éviter d'utilsiser l'unité 'SysUtils'. Ca m'énerve de rajouter une unité rien que pour une fonction ;)

- Je vais étudier TMask. Merci pour ce conseil.

- Je voulais parler des langages comme Perl où les expressions régulières font partie intégrante du langage; c'est plus simple à manipuler. Mais après vérification, tu as raison. Il semble bien que ce soit le seul langage offrant cette facilité.
Mes premières impressions: un code 100% fonctionnel qui remplit très bien son rôle tout en restant "simple" et concis.
Du Cari à l'état pur, quoi !
Cette fonction MatchesMask() (sûrement la moins bien documentée de l'aide de Delphi) permet donc bien de faire des prouesses.

A noter quelques détails:
- J'ai eu besoin de désactiver le "range checking" pour pouvoir exécuter ChercherIP() car la ligne "while MatchesMask(S[M]+S[M+1],'[0-9.][0-9.]') and (M<Length(S)) do inc(M);" lit en dehors de la chaîne (pas bien ! ^^). Par ailleurs, j'en profite pour dire que cette directive devrait toujours être active, ça évite bien des dégâts.

- C'est quoi cette ligne "Str(GetTickCount-Deb,S);" ??? On utilise IntToStr() à la place ! Et puis comme ça, tu évites ta variable "S". Enfin, c'est pas le plus important.

- Pour avoir toujours plus de performances, tu peux utiliser un objet TMask (toujours dans Masks.pas) qui te permet d'interpréter la chaîne de masque une seule fois dans toute la fonction. Ainsi, tu vas beaucoup plus vite.

- Pour certains traitements, les expressions régulières restent incontournables, mais ça, tu l'as déjà dit toi même. Par contre, ce ne sont pas "les expressions régulières des autres langages" comme tu le dis car il existe des librairies qui permettent d'utiliser les regex (compatible prce en plus) depuis Delphi.

A+
Flo