Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

COMPARAISON "INTELLIGENTE" ET MOTEUR DE RECHERCHE


Information sur la source

Catégorie :Texte Classé sous : distance, chaines Niveau : Débutant Date de création : 17/08/2006 Date de mise à jour : 21/08/2006 14:22:30 Vu / téléchargé: 3 948 / 696

Note :
9 / 10 - par 1 personne
9,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (8)
Ajouter un commentaire et/ou une note

Description

Cliquez pour voir la capture en taille normale
Dans ce source vous trouverez l'unité SmartCompare. Elle définit la fonction

function SmartDist(s1,s2:string):Double;overload;

Cette fonction retourne un nombre inférieur ou égal à 1 (lorsque les 2 chaînes sont égales) calculant la distance entre les 2 chaînes de caractères s1 et s2. La comparaison est "intelligente" en ce sens qu'elle calcule le nombre de tronçons maximaux que les 2 chaînes ont en commun, et introduit une pénalité dépendant du nombre de tronçons et de leur écartement. L'utilité de tout ça est qu'on peut s'en servir pour définir un moteur de recherche pouvant trouver des termes ayant une orthographe très proche (voir l'exemple). Plus le résultat est proche de 1, plus les 2 chaînes sont proches.

La fonction est définie mathématiquement par récurrence, mais je l'ai optimisée pour que ça aille très vite.
 

Source

  • unit SmartCompare;
  • interface
  • type
  • TEqualityFunc=function(const x,y:Integer):Boolean;
  • function SmartDist(f:TEqualityFunc;n1,n2:Integer):Double;overload;
  • function SmartDist(s1,s2:string):Double;overload;
  • implementation
  • function Max3(a,b,c:Integer):Integer;
  • begin
  • if a>b then begin
  • if a>c then
  • Result:=a
  • else
  • Result:=c;
  • end else begin
  • if b>c then
  • Result:=b
  • else
  • Result:=c;
  • end;
  • end;
  • function SmartDist(f:TEqualityFunc;n1,n2:Integer):Double;
  • var
  • i,j,a,b,c:Integer;
  • T:array[0..1] of PIntegerArray;
  • u:Boolean;
  • begin
  • GetMem(T[0],(n1+1)*(n2+1)*SizeOf(Integer));
  • GetMem(T[1],(n1+1)*(n2+1)*SizeOf(Integer));
  • for i:=0 to n1 do begin
  • T[0,i]:=0;
  • T[1,i]:=-1;
  • end;
  • for j:=0 to n2 do begin
  • T[0,j*(n1+1)]:=0;
  • T[1,j*(n1+1)]:=-1;
  • end;
  • T[1,0]:=0;
  • for i:=1 to n1 do
  • for j:=1 to n2 do begin
  • u:=f(i-1,j-1);
  • if u then
  • a:=2+T[1,i-1+(j-1)*(n1+1)]
  • else
  • a:=T[0,i-1+(j-1)*(n1+1)];
  • b:=T[0,i+(j-1)*(n1+1)];
  • c:=T[0,i-1+j*(n1+1)];
  • T[0,i+j*(n1+1)]:=Max3(a,b,c);
  • if u then
  • a:=2+T[1,i-1+(j-1)*(n1+1)]
  • else
  • a:=T[0,i-1+(j-1)*(n1+1)]-1;
  • b:=T[0,i+(j-1)*(n1+1)]-1;
  • c:=T[0,i-1+j*(n1+1)]-1;
  • T[1,i+j*(n1+1)]:=Max3(a,b,c);
  • end;
  • Result:=(n1+n2-T[1,n1+n2*(n1+1)])/(n1+n2);
  • FreeMem(T[0]);
  • FreeMem(T[1]);
  • end;
  • var
  • GS1,GS2:string;
  • function CompareStr(const x,y:Integer):Boolean;
  • begin
  • Result:=GS1[x+1]=GS2[y+1];
  • end;
  • function SmartDist(s1,s2:string):Double;overload;
  • begin
  • GS1:=s1;
  • GS2:=s2;
  • Result:=SmartDist(CompareStr,Length(s1),Length(s2));
  • GS1:=''; // Decrement reference count
  • GS2:='';
  • end;
  • end.
unit SmartCompare;

interface

type
  TEqualityFunc=function(const x,y:Integer):Boolean;

function SmartDist(f:TEqualityFunc;n1,n2:Integer):Double;overload;
function SmartDist(s1,s2:string):Double;overload;

implementation

function Max3(a,b,c:Integer):Integer;
begin
  if a>b then begin
    if a>c then
      Result:=a
    else
      Result:=c;
  end else begin
    if b>c then
      Result:=b
    else
      Result:=c;
  end;
end;

function SmartDist(f:TEqualityFunc;n1,n2:Integer):Double;
var
  i,j,a,b,c:Integer;
  T:array[0..1] of PIntegerArray;
  u:Boolean;
begin
  GetMem(T[0],(n1+1)*(n2+1)*SizeOf(Integer));
  GetMem(T[1],(n1+1)*(n2+1)*SizeOf(Integer));
  for i:=0 to n1 do begin
    T[0,i]:=0;
    T[1,i]:=-1;
  end;
  for j:=0 to n2 do begin
    T[0,j*(n1+1)]:=0;
    T[1,j*(n1+1)]:=-1;
  end;
  T[1,0]:=0;
  for i:=1 to n1 do
    for j:=1 to n2 do begin
      u:=f(i-1,j-1);
      if u then
        a:=2+T[1,i-1+(j-1)*(n1+1)]
      else
        a:=T[0,i-1+(j-1)*(n1+1)];
      b:=T[0,i+(j-1)*(n1+1)];
      c:=T[0,i-1+j*(n1+1)];
      T[0,i+j*(n1+1)]:=Max3(a,b,c);
      if u then
        a:=2+T[1,i-1+(j-1)*(n1+1)]
      else
        a:=T[0,i-1+(j-1)*(n1+1)]-1;
      b:=T[0,i+(j-1)*(n1+1)]-1;
      c:=T[0,i-1+j*(n1+1)]-1;
      T[1,i+j*(n1+1)]:=Max3(a,b,c);
    end;
  Result:=(n1+n2-T[1,n1+n2*(n1+1)])/(n1+n2);
  FreeMem(T[0]);
  FreeMem(T[1]);
end;

var
  GS1,GS2:string;

function CompareStr(const x,y:Integer):Boolean;
begin
  Result:=GS1[x+1]=GS2[y+1];
end;

function SmartDist(s1,s2:string):Double;overload;
begin
  GS1:=s1;
  GS2:=s2;
  Result:=SmartDist(CompareStr,Length(s1),Length(s2));
  GS1:='';  // Decrement reference count 
  GS2:='';
end;

end.

Conclusion

A noter: il existe une fonction overloadée du même nom qui travaille sur une fonction de comparaison quelconque (de cette façon-là, il est donc possible de travailler dur des données qui n'ont rien à voir avec des chaînes de caractères).

Ah oui une dernière chose: le texte utilisé dans l'exemple est tiré de Lovecraft (pas de copyright, donc :-)

 

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

Historique

21 août 2006 14:22:30 :
Il y avait un bug dans ma fonction (même si ça fonctionnait à peu près). Nouvelle version avec des explications en PDF.

Commentaires et avis

signaler à un administrateur
Commentaire de jinh68 le 18/08/2006 11:03:43

Tiens tiens, pas mal du tout.
Cela ressemble vaguement à la manière dont opére l'outil diff pour les différences de fichier(algorithme de Myers). Une matrice avec une chaîne sur la longueur, l'autre sur la largeur, et on trace son chemin en fonction des similitudes(un graphe en gros).

signaler à un administrateur
Commentaire de jinh68 le 18/08/2006 12:53:22

Le plus simple pour commenter à mon avis serait un shéma d'ailleurs.

signaler à un administrateur
Commentaire de Forman le 18/08/2006 14:54:49

@Jinh: Effectivement, ce code est inspiré de la distance de Levenshtein, aussi appelée "string distance" qui est utilisée dans les algo de Diff. Certes celle-ci est très bien adaptée aux comparaisons de sources par exemple, pour déterminer avec le moins d'opérations possible une séquence de suppressions/insertions de caractères (ou lignes) permettant de passer d'une version à une autre d'un texte. Mais je trouvais que ce n'était pas assez pertinent dans le cas d'une comparaison "élastique". En effet, par exemple:

exact -> exactement (distance 5 car 5 insertions)
exact -> le         (distance 5 aussi car une suppression et 4 insertions)

J'ai donc défini ma distance à partir d'un relation de récurrence un peu semblable, mais qui fait intervenir le nombre de tronçons ajouttés/supprimés plutôt que le nombre de caractères. Le problème, c'est que ça fait un moment, et je ne me souviens plus exactement comment je la justifiais... Et vu que l'algo est optimisé, ça n'aide pas beaucoup pour retrouver la justification. Je vais regarder chez moi, j'avais noté ça quelque part et peut-être que je l'ai encore.

@Florenth: Ok, je l'ai bien cherché avec mon défi de l'autre jour     :-)
Je vais remplacer mon code par le tien

signaler à un administrateur
Commentaire de Forman le 21/08/2006 14:24:20

Ca y est j'ai mis le source à jour avec ta fonction Florenth. J'ai corrigé un petit bug dans la fonction de comparaison (c'est même curieux que ça ait fonctionné ainsi...).

Jinh: Il y a un PDF dans le zip avec des explications

signaler à un administrateur
Commentaire de jinh68 le 21/08/2006 14:39:56

Nickel merci ;).

signaler à un administrateur
Commentaire de kam_2006 le 21/08/2006 19:09:31

Bonsoir

Intéréssant, je veux tester cette source

signaler à un administrateur
Commentaire de PoulpHunter le 29/08/2008 01:54:51 9/10

Essai avec cet algo :
http://www.delphifr.com/codes/DISTANCE-JARO-WINKLER_47794.aspx

expliqué ici :
http://fr.wikipedia.org/wiki/Distance_de_Jaro-Winkler

sinon ta source est vraiment bien présentée ! explication mathématique bien sympa !

signaler à un administrateur
Commentaire de Forman le 29/08/2008 02:12:44

Merci.

Ca a l'air bien efficace cette méthode de Jaro-Winkler!

Ajouter un commentaire

Discussions en rapport avec ce code source dans le forum

Actionner et arrêter une application sur un poste à distance [ par thierry ] SalutMeme question j'ai essaye ICS sous CBUILDER avec l'exemple de Chat donné .Mon programme compare la chaine recu au nom du programmeà lancer sur le Faire executer une appli a distance [ par slhuilli ] Quelu'un saurait il s'il est possible a partir d'un poste (PC1) de faire executer et de terminer une tache sur un autre poste (PC2), sachant que ces d Probleme de chaines [ par manu00 ] Bonjour tout le monde. J'ai 2 petits soucis avec mes chaines.Tout d'abord, j'aimerai stocker dans une variable 2 lignes d'un fichier texte. (il y a 2 problemes de timer et ntmstrm [ par crogger ] Bonjour, je fais de la capture d ecran que je convertit en jpg, et que je transmet en stream avec le composant NMSTRM de fastnet pour recuperer a dist Modification d'une ressource [ par tao ] Voilà,j'ai placé des chaines de caractéres dans un fichier ressources(toto.res). Chaines que j'appelle de mon programme via la fonction loadstr(..).Je Assistance a distance [ par SlunBreak ] Bonjours, Je cherche le moyen d'inserer une fonction d'assistance à distance sur un programme utilisant les composants ClientSocket et ServerSocket. L Compiler à distance [ par FleX2009 ] Bonjour, j'aurai besoin de compiler à distance une DLL Delphi, c'est-à-dire faire une application qui compile automatiquement du code Delphi Verifier le lancement d'un service à distance [ par abdouinf ] Bonjour à tous,je suis en train de developper une application Client/Serveur avec TSocketConnection, j'ai un service qui tourne sur le serveur po controle d'un pc à distance [ par templeofboom ] bonjour je suis débutant en delphi et j'aimerais savoir si l'on peu peu prendre le controle d'une machine à distance lorsqu'on connait son a acces a distance [ par exyacc ] salut, je voudrais que mon prog delphi ajoute un acces a distance ds les connexions reseau avec un num de tel, login et pass.  en fait , c'est p


Nos sponsors

Sondage...

CalendriCode

Octobre 2008
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Téléchargements



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel BAÏSE, Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,50 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.