<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Philben - Ms Access &#187; Similarité</title>
	<atom:link href="https://blog.developpez.com/philben/ptag/similarite/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/philben</link>
	<description></description>
	<lastBuildDate>Thu, 26 Sep 2013 19:43:53 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>VBA : Exemple comparatif des indices de similarité</title>
		<link>https://blog.developpez.com/philben/p12219/vba-access/vba-exemple-comparatif-des-indices-de-similarite</link>
		<comments>https://blog.developpez.com/philben/p12219/vba-access/vba-exemple-comparatif-des-indices-de-similarite#comments</comments>
		<pubDate>Sat, 07 Sep 2013 17:38:26 +0000</pubDate>
		<dc:creator><![CDATA[philben]]></dc:creator>
				<category><![CDATA[SQL - Ms Access]]></category>
		<category><![CDATA[VBA - Ms Access]]></category>
		<category><![CDATA[Algorithme]]></category>
		<category><![CDATA[Chaîne de caractères]]></category>
		<category><![CDATA[Code VBA]]></category>
		<category><![CDATA[Similarité]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/philben/?p=772</guid>
		<description><![CDATA[Après avoir vu différents algorithmes de similarité dans des billets précédents, je vous propose un petit comparatif à travers un exemple qui consiste à trouver le doublon de restaurants par leur nom, adresse, téléphone et type de cusine. Les données &#8230; <a href="https://blog.developpez.com/philben/p12219/vba-access/vba-exemple-comparatif-des-indices-de-similarite">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Après avoir vu différents algorithmes de similarité dans des billets précédents, je vous propose un petit comparatif à travers un exemple qui consiste à trouver le doublon de restaurants par leur nom, adresse, téléphone et type de cusine.<br />
<span id="more-772"></span><br />
<strong>Les données</strong><br />
Les données sont issues d&rsquo;un exemple connu de recherche de doublons et sont présentées ici dans une seule colonne où nom, adresse, téléphone et type de cuisine sont fusionnés. <a href="http://philben.developpez.com/restos.txt" title="Fichier texte des restaurants" target="_blank">Le fichier de données</a> contient 224 lignes et chaque resto possède un et un seul doublon. Cet exemple reste donc plus simple qu&rsquo;un cas général de recherche de doublons&#8230;<br />
Extrait du fichier :</p>
<div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Katsu 1972 Hillhurst Ave. Los Feliz 213-665-1891 Japanese<br />
Restaurant Katsu 1972 N. Hillhurst Ave. Los Angeles 213/665-1891 Asian<br />
Les Celebrites 155 W. 58th St. New York City 212-484-5113 French (Classic)<br />
Les C&amp;eacute;l&amp;eacute;brit&amp;eacute;s 160 Central Park S New York 212/484-5113 French</div></div>
<p>Une difficulté s&rsquo;ajoute pour le dernier restaurant car les &lsquo;é&rsquo; de Célébrités sont convertis en HTML (&amp; eacute;)&#8230;</p>
<p>Le fichier source original est <a href="http://www.cs.utexas.edu/users/ml/riddle/data/restaurant.tar.gz" title="Fichier source des restaurants" target="_blank">ici</a>.</p>
<p><strong>Principe</strong><br />
Le principe est donc de rechercher pour chaque ligne, le restaurant qui a la similarité la plus forte soit 49 952 mesures (224 x 223) après conversion des chaînes en majuscule.<br />
Pour chaque restaurant, je considère que le bon doublon a été correctement trouvé s&rsquo;il arrive avec le plus fort indice par rapport aux 222 autres restaurants.<br />
J&rsquo;ai comparé les 3 algorithmes <a href="http://blog.developpez.com/philben/p12207/vba-access/vba-distance-de-jaro-winkler" title="VBA : Distance de Jaro-Winkler" target="_blank">Jaro-Winkler (JW)</a>, <a href="http://blog.developpez.com/philben/p11268/vba-access/similarite_entre_deux_chaines_de_caracte" title="Similarité entre deux chaînes de caractères" target="_blank">Damerau-Levenshtein (DL)</a> et les <a href="http://blog.developpez.com/philben/p11340/vba-access/indices-de-similarite-entre-deux-chaines-de-caracteres" title="Indices de similarité entre deux chaînes de caractères" target="_blank">6 indices Cosinus/Dice/Jaccard/&#8230; (IS)</a>, en recherchant pour chacun la meilleure configuration.</p>
<p><strong>Résultats</strong><br />
Concernant DL, pas de problème pour trouver la meilleure configuration car il suffit de passer les 2 chaînes en argument de la fonction.<br />
<strong>Damerau-Levenshtein a permis de détecter <strong>185 doublons sur 224 soit 82,6%</strong> de réussite.</strong></p>
<p>Concernant Jaro-Winkler, on peut jouer sur la longueur du préfixe entre 0 et 4. Les résultats obtenus sont :</p>
<div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Longueur préfixe &nbsp; &nbsp; &nbsp; &nbsp;Doublons détectés<br />
&nbsp; &nbsp; &nbsp; &nbsp; 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 206<br />
&nbsp; &nbsp; &nbsp; &nbsp; 1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 209<br />
&nbsp; &nbsp; &nbsp; &nbsp; 2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 214<br />
&nbsp; &nbsp; &nbsp; &nbsp; 3 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 213<br />
&nbsp; &nbsp; &nbsp; &nbsp; 4 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 212</div></div>
<p>Dans cet exemple, la <strong>meilleure longueur de préfixe est 2 avec 214 doublons détectés soit un taux de réussite de 95,5%</strong>, la distance de Jaro seule (0) donne le moins bon résultat.</p>
<p>Enfin pour l&rsquo;algorithme IS, le choix du paramétrage est plus complexe car on peut choisir entre 6 indices de similarités, la longueur des Grammes (0 = mot à 5), l&rsquo;inversion ou non des grammes et une distance maximum de recherche des grammes communs.<br />
Pour la distance maxi, j&rsquo;ai laissé à -1 (pas de limite de distance) car elle fournit les meilleurs résultats dans cet exemple et la recherche de grammes inversés donne ici de moins bons résultats.</p>
<p>J&rsquo;ai donc joué sur le reste des paramètres (type d&rsquo;indice et longueur des grammes) et les résultats sont synthétisés ici :<br />
<img src="http://philben.developpez.com/restos.png" alt="Paramétrage des indices de similarité et résultats" /><br />
Les unigrammes (1) ont les moins bon résultats, la variabilité des résultats entre les indices diminue avec la longueur des grammes, les trigrammes et Simpson ont en moyenne les meilleurs résultats.</p>
<p>Pourcentage de réussite des indices en fonction de la longueur des grammes :<br />
<img src="http://philben.developpez.com/restosGraphe.png" alt="Pourcentage de réussites des indices en fonction de la longueur des grammes" /><br />
<strong>Finalement, l&rsquo;indice de Simpson avec des bigrammes donne ici le meilleur résultat : 219 doublons détectés soit 97,8% de réussite !</strong></p>
<p>Le tableau suivant indique le nombre de doublons détectés par position des résultats hormis le Top 1. Par exemple, 18 nouvelles bonnes détections faites par DL dans les Top 2 des résultats et <strong>Simpson en détecte 4 soit 223 détections cumulées (Top 1 et Top 2) sur 224 !</strong>.<br />
<img src="http://philben.developpez.com/restosPositions.png" alt="Nombre de détections en fonction de la position des résultats" /></p>
<p>Après avoir vu rapidement la capacité des indices à détecter les vrais doublons, il faut vérifier leur capacité à être discriminant entre les restaurants et compter les éventuels ex aequo.<br />
Imaginez un algo qui retourne un indice identique pour tous les restos : Ses résultats seraient parfaits mais pour chaque restaurant on aurait 223 restaurants détectés dans le Top 1 !</p>
<p>Via une requête, j&rsquo;ai donc calculé la position absolue du vrai doublon pour chaque algorithme et chaque ligne. Des ex aequo sont présents si la position absolue est supérieure au classement.</p>
<div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Indice&nbsp; Classement &nbsp; Position absolue<br />
---------------------------------------<br />
JW&nbsp; &nbsp; &nbsp; 28 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;29<br />
---------------------------------------<br />
IS&nbsp; &nbsp; &nbsp; &nbsp;1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2<br />
---------------------------------------<br />
DL&nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3<br />
DL&nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4<br />
DL&nbsp; &nbsp; &nbsp; &nbsp;3 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6<br />
DL&nbsp; &nbsp; &nbsp; &nbsp;4 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6<br />
DL&nbsp; &nbsp; &nbsp; &nbsp;4 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5<br />
DL&nbsp; &nbsp; &nbsp; &nbsp;5 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 9<br />
DL&nbsp; &nbsp; &nbsp; &nbsp;5 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6<br />
DL&nbsp; &nbsp; &nbsp; &nbsp;6 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 7<br />
DL&nbsp; &nbsp; &nbsp; &nbsp;7 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;12<br />
DL&nbsp; &nbsp; &nbsp; &nbsp;9 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;11<br />
DL&nbsp; &nbsp; &nbsp; 12 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;20<br />
DL&nbsp; &nbsp; &nbsp; 17 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;21<br />
DL&nbsp; &nbsp; &nbsp; 24 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;66</div></div>
<p>JW n&rsquo;est affecté qu&rsquo;une fois par un ex aequo et ceci pour un classement du vrai doublon en 28ème position.<br />
IS en a obtenu un seul sur un Top 1 et DL a eu 13 fois un ou plusieurs ex aequo.</p>
<p><strong>Conclusion</strong><br />
Dans cet exemple, l&rsquo;indice de Simpson a détecté le plus de doublons dans le Top 1 (219 sur 224) et 223 dans le Top 2 des résultats.<br />
Si vous le souhaitez, vous pouvez ajouter <strong>vos propres résultats</strong> de vos algorithmes en commentaire du billet.</p>
<p>@+</p>
<p>Philippe</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>VBA : Distance de Jaro-Winkler</title>
		<link>https://blog.developpez.com/philben/p12207/vba-access/vba-distance-de-jaro-winkler</link>
		<comments>https://blog.developpez.com/philben/p12207/vba-access/vba-distance-de-jaro-winkler#comments</comments>
		<pubDate>Sat, 31 Aug 2013 03:01:16 +0000</pubDate>
		<dc:creator><![CDATA[philben]]></dc:creator>
				<category><![CDATA[SQL - Ms Access]]></category>
		<category><![CDATA[VBA - Ms Access]]></category>
		<category><![CDATA[Algorithme]]></category>
		<category><![CDATA[Chaîne de caractères]]></category>
		<category><![CDATA[Code VBA]]></category>
		<category><![CDATA[Similarité]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/philben/?p=703</guid>
		<description><![CDATA[Cet algorithme mesure la similarité entre deux chaînes de caractères pour la recherche de doublons par exemple. Tout comme les algorithmes de Damerau-Levenshtein et les indices de similarité Cosinus, Dice, Jaccard&#8230;, la distance est normalisée entre 0 et 1. Plus &#8230; <a href="https://blog.developpez.com/philben/p12207/vba-access/vba-distance-de-jaro-winkler">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Cet algorithme mesure la similarité entre deux chaînes de caractères pour la recherche de doublons par exemple. Tout comme les algorithmes de <a href="http://blog.developpez.com/philben/p11268/vba-access/similarite_entre_deux_chaines_de_caracte" title="Similarité entre deux chaînes de caractères" target="_blank">Damerau-Levenshtein</a> et les <a href="http://blog.developpez.com/philben/p11340/vba-access/indices-de-similarite-entre-deux-chaines-de-caracteres" title="Indices de similarité entre deux chaînes de caractères" target="_blank">indices de similarité Cosinus, Dice, Jaccard&#8230;</a>, la distance est normalisée entre 0 et 1. Plus la similarité est forte plus la distance tend vers 1.<br />
<span id="more-703"></span><br />
<strong>La fonction VBA</strong></p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:400px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #E56717; font-weight: bold;">Public</span> <span style="color: #E56717; font-weight: bold;">Function</span> JaroWinkler(<span style="color: #151B8D; font-weight: bold;">ByVal</span> s1 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span>, <span style="color: #151B8D; font-weight: bold;">ByVal</span> s2 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span>, _<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> LongueurPrefixe <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Byte</span> = 3, _<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> TypeComparaison <span style="color: #151B8D; font-weight: bold;">As</span> VbCompareMethod = vbBinaryCompare) <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Single</span><br />
<span style="color: #008000;">'La distance de jaro_Winkler mesure la similarité entre deux chaines de caractères (s1 et s2)<br />
</span><span style="color: #008000;">'La distance est normalisée entre 0 et 1 (1 = similarité maximale)<br />
</span><span style="color: #008000;">'si LongueurPrefixe [0,4] = 0 =&gt; Distance de Jaro<br />
</span><span style="color: #008000;">'Référence : http://fr.wikipedia.org/wiki/Distance_de_Jaro-Winkler et références<br />
</span><span style="color: #008000;">'Remarques : Préparation parfois nécessaire des chaînes : ucase(),trim(),diacritiques<br />
</span><span style="color: #008000;">' &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Quelques libertés prises pour le calcul de la fenêtre (dMax) / Wikipédia<br />
</span><span style="color: #008000;">'Auteur : Philben v1.0 - Free to use<br />
</span> &nbsp; Const cMaxLongueurPrefixe <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Byte</span> = 4, cCoeffPrefixe <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Single</span> = 0.1<br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> l1 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, l2 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, dMax <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, i <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, j <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, k <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span><br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> jMin <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, jMax <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, m <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, t <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, p <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, lam1 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span><br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> c1 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span>, r <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Single</span>, aUsed() <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Boolean</span>, ac2() <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span>, am1() <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span><br />
<br />
&nbsp; &nbsp;l1 = Len(s1): l2 = Len(s2)<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> l1 &gt; 0 <span style="color: #8D38C9; font-weight: bold;">And</span> l2 &gt; 0 <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">ReDim</span> aUsed(1 <span style="color: #8D38C9; font-weight: bold;">To</span> l2): <span style="color: #151B8D; font-weight: bold;">ReDim</span> ac2(1 <span style="color: #8D38C9; font-weight: bold;">To</span> l2)<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">For</span> i = 1 <span style="color: #8D38C9; font-weight: bold;">To</span> l2: ac2(i) = Mid$(s2, i, 1): <span style="color: #8D38C9; font-weight: bold;">Next</span> i<br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> l1 &gt;= l2 <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #008000;">'dMax (1/2 fenêtre) calculée avec la + courte chaîne et non la + longue ! (voir blog)<br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; dMax = (l2 + 1) \ 2 - 1 &nbsp; <span style="color: #008000;">'arrondi sup. de dMax (l=1 =&gt; 0, l=2 =&gt; 0, l=3 =&gt; 1)<br />
</span> &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dMax = (l1 + 1) \ 2 - 1<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> LongueurPrefixe &gt; cMaxLongueurPrefixe <span style="color: #8D38C9; font-weight: bold;">Then</span> LongueurPrefixe = cMaxLongueurPrefixe<br />
<br />
&nbsp; &nbsp; &nbsp; jMin = 1<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> dMax &lt; l2 <span style="color: #8D38C9; font-weight: bold;">Then</span> jMax = dMax <span style="color: #8D38C9; font-weight: bold;">Else</span>: jMax = l2<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">For</span> i = 1 <span style="color: #8D38C9; font-weight: bold;">To</span> l1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;c1 = Mid$(s1, i, 1)<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> i &gt; dMax + 1 <span style="color: #8D38C9; font-weight: bold;">Then</span> jMin = jMin + 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> jMax &lt; l2 <span style="color: #8D38C9; font-weight: bold;">Then</span> jMax = jMax + 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> jMin &gt; jMax <span style="color: #8D38C9; font-weight: bold;">Then</span> <span style="color: #E56717; font-weight: bold;">Exit</span> <span style="color: #8D38C9; font-weight: bold;">For</span> &nbsp; <span style="color: #008000;">'définitivement hors fenêtre =&gt; Fin<br />
</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">For</span> j = jMin <span style="color: #8D38C9; font-weight: bold;">To</span> jMax<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> <span style="color: #8D38C9; font-weight: bold;">Not</span> aUsed(j) <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> StrComp(c1, ac2(j), TypeComparaison) = 0 <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m = m + 1 &nbsp; <span style="color: #008000;">'Match<br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> i = j <span style="color: #8D38C9; font-weight: bold;">And</span> i &lt;= LongueurPrefixe <span style="color: #8D38C9; font-weight: bold;">And</span> p = i - 1 <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;p = p + 1 &nbsp;<span style="color: #008000;">'Préfixe commun<br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;lam1 = lam1 + 1: <span style="color: #151B8D; font-weight: bold;">ReDim</span> <span style="color: #151B8D; font-weight: bold;">Preserve</span> am1(1 <span style="color: #8D38C9; font-weight: bold;">To</span> lam1): am1(lam1) = i<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; aUsed(j) = <span style="color: #00C2FF; font-weight: bold;">True</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #E56717; font-weight: bold;">Exit</span> <span style="color: #8D38C9; font-weight: bold;">For</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Next</span> j<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Next</span> i<br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #008000;">'Compte les tranpositions<br />
</span> &nbsp; &nbsp; &nbsp;k = p + 1<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">For</span> i = 1 <span style="color: #8D38C9; font-weight: bold;">To</span> lam1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">For</span> j = k <span style="color: #8D38C9; font-weight: bold;">To</span> l2<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> aUsed(j) <span style="color: #8D38C9; font-weight: bold;">Then</span> <span style="color: #E56717; font-weight: bold;">Exit</span> <span style="color: #8D38C9; font-weight: bold;">For</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Next</span> j<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> StrComp(Mid$(s1, am1(i), 1), ac2(j), TypeComparaison) &lt;&gt; 0 <span style="color: #8D38C9; font-weight: bold;">Then</span> t = t + 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;k = j + 1<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Next</span> i<br />
&nbsp; &nbsp; &nbsp; t = t \ 2<br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> m &gt; 0 <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;r = (m / l1 + m / l2 + (m - t) / m) / 3 &nbsp; <span style="color: #008000;">'Distance de Jaro<br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; r = r + (p * cCoeffPrefixe * (1 - r)) &nbsp; <span style="color: #008000;">'Extension de Winkler<br />
</span> &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
<br />
&nbsp; &nbsp;JaroWinkler = r<br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></div></div>
<p>&nbsp;<br />
<strong>Paramètres de la fonction</strong><br />
<strong>&lsquo;S1&prime; et &lsquo;S2&prime;</strong> correspondent aux deux chaînes de caractères à étudier.<br />
<strong>&lsquo;LongueurPrefixe&rsquo;</strong> permet de choisir la longueur du préfixe commun entre les deux chaînes. Cette longueur permet de calculer l&rsquo;apport de Winkler à l&rsquo;algorithme de Jaro. Cette longueur est comprise entre 0 et 4 (3 par défaut). La distance de Jaro est retournée lorsque ce paramètre est égal à 0.<br />
<strong>&lsquo;TypeComparaison&rsquo;</strong> permet de choisir le type de comparaison entre les deux chaînes : Soit une comparaison binaire (par défaut) soit une comparaison textuelle (moins restrictive car ne tient pas compte de la casse des caractères mais généralement moins performante).<br />
Il sera souvent nécessaire de prétraiter les chaînes par UCase()/LCase() (casse uniforme des caractères), Trim() (suppression des espaces en début et fin de chaîne) et remplacer les caractères diacritiques pour ne pas &lsquo;parasiter&rsquo; l&rsquo;algorithme (voir <a href="http://blog.developpez.com/philben/p11217/vba-access/remplacer_les_caracteres_accentues_d_une" title="Remplacer les caractères accentués d’une chaîne" target="_blank">ici</a>).</p>
<p><strong>Tests</strong><br />
J&rsquo;ai récolté dans une publication de W. E. Winkler (voir référence plus bas) et sur le Web des exemples pour tester les résultats de mon code. La longueur du préfixe est fixée à 4.</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #E56717; font-weight: bold;">Public</span> <span style="color: #E56717; font-weight: bold;">Function</span> testJW()<br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> i <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, r <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Single</span>, v() <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Variant</span><br />
<br />
&nbsp; &nbsp;v = Array(<span style="color: #800000;">&quot;SHACKLEFORD&quot;</span>, <span style="color: #800000;">&quot;SHACKELFORD&quot;</span>, 0.982, <span style="color: #800000;">&quot;DUNNINGHAM&quot;</span>, <span style="color: #800000;">&quot;CUNNIGHAM&quot;</span>, 0.896, <span style="color: #800000;">&quot;NICHLESON&quot;</span>, <span style="color: #800000;">&quot;NICHULSON&quot;</span>, 0.956, _<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #800000;">&quot;JONES&quot;</span>, <span style="color: #800000;">&quot;JOHNSON&quot;</span>, 0.832, <span style="color: #800000;">&quot;MASSEY&quot;</span>, <span style="color: #800000;">&quot;MASSIE&quot;</span>, 0.933, <span style="color: #800000;">&quot;ABROMS&quot;</span>, <span style="color: #800000;">&quot;ABRAMS&quot;</span>, 0.922, <span style="color: #800000;">&quot;HARDIN&quot;</span>, <span style="color: #800000;">&quot;MARTINEZ&quot;</span>, 0#, _<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #800000;">&quot;ITMAN&quot;</span>, <span style="color: #800000;">&quot;SMITH&quot;</span>, 0#, <span style="color: #800000;">&quot;JERALDINE&quot;</span>, <span style="color: #800000;">&quot;GERALDINE&quot;</span>, 0.926, <span style="color: #800000;">&quot;MARHTA&quot;</span>, <span style="color: #800000;">&quot;MARTHA&quot;</span>, 0.961, <span style="color: #800000;">&quot;MICHELLE&quot;</span>, <span style="color: #800000;">&quot;MICHAEL&quot;</span>, 0.921, _<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #800000;">&quot;JULIES&quot;</span>, <span style="color: #800000;">&quot;JULIUS&quot;</span>, 0.933, <span style="color: #800000;">&quot;TANYA&quot;</span>, <span style="color: #800000;">&quot;TONYA&quot;</span>, 0.88, <span style="color: #800000;">&quot;DWAYNE&quot;</span>, <span style="color: #800000;">&quot;DUANE&quot;</span>, 0.84, <span style="color: #800000;">&quot;SEAN&quot;</span>, <span style="color: #800000;">&quot;SUSAN&quot;</span>, 0.805, _<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #800000;">&quot;JON&quot;</span>, <span style="color: #800000;">&quot;JOHN&quot;</span>, 0.933, <span style="color: #800000;">&quot;JON&quot;</span>, <span style="color: #800000;">&quot;JAN&quot;</span>, 0#, <span style="color: #800000;">&quot;DIXON&quot;</span>, <span style="color: #800000;">&quot;DICKSONX&quot;</span>, 0.813, <span style="color: #800000;">&quot;VOYAGE&quot;</span>, <span style="color: #800000;">&quot;AGENDA&quot;</span>, 0.444, _<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #800000;">&quot;TRAVEL&quot;</span>, <span style="color: #800000;">&quot;TRAIN&quot;</span>, 0.9, <span style="color: #800000;">&quot;ABCVWXYZ&quot;</span>, <span style="color: #800000;">&quot;CABVWXYZ&quot;</span>, 0.958)<br />
<br />
&nbsp; &nbsp;Debug.<span style="color: #151B8D; font-weight: bold;">Print</span> <span style="color: #800000;">&quot;Chaîne 1&quot;</span>, <span style="color: #800000;">&quot;Chaîne 2&quot;</span>, <span style="color: #800000;">&quot;Attendue&quot;</span>, <span style="color: #800000;">&quot;Obtenue&quot;</span><br />
&nbsp; &nbsp;Debug.<span style="color: #151B8D; font-weight: bold;">Print</span> <span style="color: #800000;">&quot;--------&quot;</span>, <span style="color: #800000;">&quot;--------&quot;</span>, <span style="color: #800000;">&quot;---------&quot;</span>, <span style="color: #800000;">&quot;-------&quot;</span><br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">For</span> i = <span style="color: #151B8D; font-weight: bold;">LBound</span>(v) <span style="color: #8D38C9; font-weight: bold;">To</span> <span style="color: #151B8D; font-weight: bold;">UBound</span>(v) <span style="color: #8D38C9; font-weight: bold;">Step</span> 3<br />
&nbsp; &nbsp; &nbsp; r = JaroWinkler(v(i), v(i + 1), 4) &nbsp; <span style="color: #008000;">'Longueur Prefixe = 4<br />
</span> &nbsp; &nbsp; &nbsp;Debug.<span style="color: #151B8D; font-weight: bold;">Print</span> v(i), v(i + 1), v(i + 2), Round(r, 3), IIf(Abs(r - v(i + 2)) &gt; 0.001, <span style="color: #800000;">&quot;*** Ecart ***&quot;</span>, <span style="color: #800000;">&quot;&quot;</span>)<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Next</span> i<br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></div></div>
<p>&nbsp;<br />
<strong>Résultats et commentaires</strong></p>
<div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Chaîne 1 &nbsp; &nbsp; &nbsp;Chaîne 2 &nbsp; &nbsp; &nbsp;Attendue &nbsp; &nbsp; &nbsp;Obtenue<br />
-------- &nbsp; &nbsp; &nbsp;-------- &nbsp; &nbsp; &nbsp;--------- &nbsp; &nbsp; -------<br />
SHACKLEFORD &nbsp; SHACKELFORD &nbsp; &nbsp;0,982 &nbsp; &nbsp; &nbsp; &nbsp; 0,982 &nbsp; &nbsp; &nbsp; &nbsp;<br />
DUNNINGHAM &nbsp; &nbsp;CUNNIGHAM &nbsp; &nbsp; &nbsp;0,896 &nbsp; &nbsp; &nbsp; &nbsp; 0,896 &nbsp; &nbsp; &nbsp; &nbsp;<br />
NICHLESON &nbsp; &nbsp; NICHULSON &nbsp; &nbsp; &nbsp;0,956 &nbsp; &nbsp; &nbsp; &nbsp; 0,956 &nbsp; &nbsp; &nbsp; &nbsp;<br />
JONES &nbsp; &nbsp; &nbsp; &nbsp; JOHNSON &nbsp; &nbsp; &nbsp; &nbsp;0,832 &nbsp; &nbsp; &nbsp; &nbsp; 0,832 &nbsp; &nbsp; &nbsp; &nbsp;<br />
MASSEY &nbsp; &nbsp; &nbsp; &nbsp;MASSIE &nbsp; &nbsp; &nbsp; &nbsp; 0,933 &nbsp; &nbsp; &nbsp; &nbsp; 0,933 &nbsp; &nbsp; &nbsp; &nbsp;<br />
ABROMS &nbsp; &nbsp; &nbsp; &nbsp;ABRAMS &nbsp; &nbsp; &nbsp; &nbsp; 0,922 &nbsp; &nbsp; &nbsp; &nbsp; 0,922 &nbsp; &nbsp; &nbsp; &nbsp;<br />
HARDIN &nbsp; &nbsp; &nbsp; &nbsp;MARTINEZ &nbsp; &nbsp; &nbsp; 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0,722 &nbsp; &nbsp; &nbsp; &nbsp;*** Ecart ***<br />
ITMAN &nbsp; &nbsp; &nbsp; &nbsp; SMITH &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0,622 &nbsp; &nbsp; &nbsp; &nbsp;*** Ecart ***<br />
JERALDINE &nbsp; &nbsp; GERALDINE &nbsp; &nbsp; &nbsp;0,926 &nbsp; &nbsp; &nbsp; &nbsp; 0,926 &nbsp; &nbsp; &nbsp; &nbsp;<br />
MARHTA &nbsp; &nbsp; &nbsp; &nbsp;MARTHA &nbsp; &nbsp; &nbsp; &nbsp; 0,961 &nbsp; &nbsp; &nbsp; &nbsp; 0,961 &nbsp; &nbsp; &nbsp; &nbsp;<br />
MICHELLE &nbsp; &nbsp; &nbsp;MICHAEL &nbsp; &nbsp; &nbsp; &nbsp;0,921 &nbsp; &nbsp; &nbsp; &nbsp; 0,921 &nbsp; &nbsp; &nbsp; &nbsp;<br />
JULIES &nbsp; &nbsp; &nbsp; &nbsp;JULIUS &nbsp; &nbsp; &nbsp; &nbsp; 0,933 &nbsp; &nbsp; &nbsp; &nbsp; 0,933 &nbsp; &nbsp; &nbsp; &nbsp;<br />
TANYA &nbsp; &nbsp; &nbsp; &nbsp; TONYA &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0,88 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0,88 &nbsp; &nbsp; &nbsp; &nbsp; <br />
DWAYNE &nbsp; &nbsp; &nbsp; &nbsp;DUANE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0,84 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0,84 &nbsp; &nbsp; &nbsp; &nbsp; <br />
SEAN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SUSAN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0,805 &nbsp; &nbsp; &nbsp; &nbsp; 0,805 &nbsp; &nbsp; &nbsp; &nbsp;<br />
JON &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; JOHN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0,933 &nbsp; &nbsp; &nbsp; &nbsp; 0,933 &nbsp; &nbsp; &nbsp; &nbsp;<br />
JON &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; JAN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0,8 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*** Ecart ***<br />
DIXON &nbsp; &nbsp; &nbsp; &nbsp; DICKSONX &nbsp; &nbsp; &nbsp; 0,813 &nbsp; &nbsp; &nbsp; &nbsp; 0,813 &nbsp; &nbsp; &nbsp; &nbsp;<br />
VOYAGE &nbsp; &nbsp; &nbsp; &nbsp;AGENDA &nbsp; &nbsp; &nbsp; &nbsp; 0,444 &nbsp; &nbsp; &nbsp; &nbsp; 0,444 &nbsp; &nbsp; &nbsp; &nbsp;<br />
TRAVEL &nbsp; &nbsp; &nbsp; &nbsp;TRAIN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0,9 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0,79 &nbsp; &nbsp; &nbsp; &nbsp; *** Ecart ***<br />
ABCVWXYZ &nbsp; &nbsp; &nbsp;CABVWXYZ &nbsp; &nbsp; &nbsp; 0,958 &nbsp; &nbsp; &nbsp; &nbsp; 0,958</div></div>
<p>&nbsp;<br />
Les distances obtenues sont parfois différentes des distances attendues (4 écarts constatés).<br />
Concernant les couples <strong>HARDIN/MARTINEZ, ITMAN/SMITH, JON/JAN</strong>, ils sont fournis par W. E. Winkler qui devait utiliser un algo un peu différent de celui décrit dans Wikipédia (en effet, sa fonction strcomp.c est plus complexe&#8230;)</p>
<p>Concernant le couple <strong>TRAVEL/TRAIN</strong> et la distance attendue de 0,9, je pense qu&rsquo;il s&rsquo;agit d&rsquo;une coquille de l&rsquo;auteur car la distance de Jaro dans la même publication était seulement de 0,7.</p>
<p>De plus, l&rsquo;applet java de <a href="http://arantxa.ii.uam.es/~dcamacho/StringDistance/StringDistance.htm" title="String Distance" target="_blank">ce site</a> donne des résultats proches ou identiques aux miens.</p>
<p><strong>Remarque</strong><br />
L&rsquo;éloignement maximal (variable dMax dans mon code) devrait être calculé à l&rsquo;aide de la plus grande longueur de chaîne. J&rsquo;ai préféré utiliser la plus courte pour éviter des résultats &lsquo;étonnants&rsquo; avec certaines chaînes de caractères.<br />
Par exemple, en allongeant la seconde chaîne &lsquo;cba&rsquo; et en utilisant la plus grande longueur des deux chaînes de caractères, on obtient :</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">?JaroWinkler(<span style="color: #800000;">&quot;abc&quot;</span>,<span style="color: #800000;">&quot;cba&quot;</span>) <span style="color: #008000;">'0,556<br />
</span>?JaroWinkler(<span style="color: #800000;">&quot;abc&quot;</span>,<span style="color: #800000;">&quot;cbau&quot;</span>) <span style="color: #008000;">'0,528<br />
</span>?JaroWinkler(<span style="color: #800000;">&quot;abc&quot;</span>,<span style="color: #800000;">&quot;cbauu&quot;</span>) <span style="color: #008000;">'0,756<br />
</span>?JaroWinkler(<span style="color: #800000;">&quot;abc&quot;</span>,<span style="color: #800000;">&quot;cbauuu&quot;</span>) '0,722</div></div>
<p>La similarité diminue avec 4 caractères (0,528) puis augmente paradoxalement avec 5 caractères (&lsquo;cbauu&rsquo; donne 0,756)!<br />
<strong>Pourquoi ?</strong><br />
<strong>Dans le 1er exemple</strong>, l&rsquo;éloignement maximal (variable dMax dans le code) est égal à 1 et on obtient une seule concordance (lettre &lsquo;b&rsquo;) entre les 2 chaînes.<br />
<strong>Dans le 2ème exemple</strong>, la similarité chute légèrement car la longueur de la chaîne n°2 est de 4 au lieu de 3 et celle-ci intervient en tant que dénominateur dans le calcul de la distance de Jaro. L&rsquo;éloignement maximal reste égal à 1.<br />
<strong>Dans le 3ème exemple</strong>, l&rsquo;éloignement maximal est égal à <strong>2</strong> car la longueur de la chaîne n°2 est de 5 caractères (arrondi supérieur de 5/2 &#8211; 1 = 2). Cet éloignement permet d&rsquo;obtenir 3 correspondances (&lsquo;a&rsquo;, &lsquo;b&rsquo;, &lsquo;c&rsquo;) et une transposition (&lsquo;a&rsquo; et &lsquo;c&rsquo;). Ces 3 correspondances au lieu d&rsquo;une seule augmentent la similarité malgré la transposition et la longueur de la chaîne n°2.</p>
<p><strong>Pour éviter ce problème</strong>, une solution consiste donc à utiliser la plus petite longueur des deux chaînes :</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">?JaroWinkler(<span style="color: #800000;">&quot;abc&quot;</span>,<span style="color: #800000;">&quot;cba&quot;</span>) <span style="color: #008000;">'0,556<br />
</span>?JaroWinkler(<span style="color: #800000;">&quot;abc&quot;</span>,<span style="color: #800000;">&quot;cbau&quot;</span>) <span style="color: #008000;">'0,528<br />
</span>?JaroWinkler(<span style="color: #800000;">&quot;abc&quot;</span>,<span style="color: #800000;">&quot;cbauu&quot;</span>) <span style="color: #008000;">'0,511<br />
</span>?JaroWinkler(<span style="color: #800000;">&quot;abc&quot;</span>,<span style="color: #800000;">&quot;cbauuu&quot;</span>) '0,5</div></div>
<p>&nbsp;<br />
<strong>Conclusion</strong><br />
Algorithme rapide et efficace sur des chaînes relativement courtes.</p>
<p><strong>Références</strong><br />
Wikipédia: <a href="http://fr.wikipedia.org/wiki/Distance_de_Jaro-Winkler" title="Jaro_Winkler sur Wikipédia" target="_blank">Distance de Jaro-Winkler</a><br />
Publication de <a href="http://www.census.gov/srd/papers/pdf/rrs2006-02.pdf" title="Overview of Record Linkage and Current Research Directions" target="_blank">W. E. Winkler</a>.</p>
<p>@+</p>
<p>Philippe</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Indices de similarité entre deux chaînes de caractères</title>
		<link>https://blog.developpez.com/philben/p11340/vba-access/indices-de-similarite-entre-deux-chaines-de-caracteres</link>
		<comments>https://blog.developpez.com/philben/p11340/vba-access/indices-de-similarite-entre-deux-chaines-de-caracteres#comments</comments>
		<pubDate>Mon, 24 Sep 2012 00:32:03 +0000</pubDate>
		<dc:creator><![CDATA[philben]]></dc:creator>
				<category><![CDATA[SQL - Ms Access]]></category>
		<category><![CDATA[VBA - Ms Access]]></category>
		<category><![CDATA[Algorithme]]></category>
		<category><![CDATA[Chaîne de caractères]]></category>
		<category><![CDATA[Code VBA]]></category>
		<category><![CDATA[Similarité]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/philben/?p=319</guid>
		<description><![CDATA[Après l&#8217;algorithme de Damerau-Levenshtein qui mesure la distance minimale d&#8217;édition entre deux textes, je présente un algorithme plus simple et donc plus rapide qui calcule différents indices de similarité (Cosinus, Dice, Jaccard, Kulczynski,&#8230;) à partir de n-grammes (n-grams/q-grams en anglais) &#8230; <a href="https://blog.developpez.com/philben/p11340/vba-access/indices-de-similarite-entre-deux-chaines-de-caracteres">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Après l&rsquo;algorithme de <a href="http://blog.developpez.com/philben/?p=19" title="Damerau-Levenshtein">Damerau-Levenshtein</a> qui mesure la distance minimale d&rsquo;édition entre deux textes, je présente un algorithme plus simple et donc plus rapide qui calcule différents indices de similarité (Cosinus, Dice, Jaccard, Kulczynski,&#8230;) à partir de n-grammes (n-grams/q-grams en anglais) ou sous-séquences continues de caractères.<br />
<span id="more-319"></span><br />
<strong>Les fonctions</strong><br />
Placer l&rsquo;ensemble du code suivant dans un module standard.<br />
&nbsp;<br />
L&rsquo;énumération pour faciliter le choix du coefficient de similarité :</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #E56717; font-weight: bold;">Public</span> <span style="color: #F660AB; font-weight: bold;">Enum</span> eIndiceSimilarite<br />
&nbsp; &nbsp;eCosinus = 1<br />
&nbsp; &nbsp;eDice = 2<br />
&nbsp; &nbsp;eJaccard = 3<br />
&nbsp; &nbsp;eKulczynski = 4<br />
&nbsp; &nbsp;eBraunBlanquet = 5<br />
&nbsp; &nbsp;eSimpson = 6<br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #F660AB; font-weight: bold;">Enum</span></div></div>
<p>&nbsp;<br />
La fonction Ngram appelée par la fonction principale pour créer les grammes de la chaîne :</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #E56717; font-weight: bold;">Private</span> <span style="color: #E56717; font-weight: bold;">Function</span> Ngram(<span style="color: #151B8D; font-weight: bold;">ByRef</span> qgs() <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span>, <span style="color: #151B8D; font-weight: bold;">ByVal</span> s <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span>, <span style="color: #151B8D; font-weight: bold;">ByVal</span> Q <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, <span style="color: #151B8D; font-weight: bold;">ByVal</span> InversionGram <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Boolean</span>) <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span><br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> i <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, n <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, Fin <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span><br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> Q &gt; 0 <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> Q &gt; 1 <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> InversionGram <span style="color: #8D38C9; font-weight: bold;">Then</span> Fin = vbVerticalTab <span style="color: #8D38C9; font-weight: bold;">Else</span>: Fin = vbFormFeed<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s = <span style="color: #F660AB; font-weight: bold;">String</span>(Q - 1, vbVerticalTab) &amp; s &amp; <span style="color: #F660AB; font-weight: bold;">String</span>(Q - 1, Fin)<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
&nbsp; &nbsp; &nbsp; n = Len(s) - Q: <span style="color: #151B8D; font-weight: bold;">ReDim</span> qgs(0 <span style="color: #8D38C9; font-weight: bold;">To</span> n)<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">For</span> i = 0 <span style="color: #8D38C9; font-weight: bold;">To</span> n: qgs(i) = Mid$(s, i + 1, Q): <span style="color: #8D38C9; font-weight: bold;">Next</span> i<br />
&nbsp; &nbsp; &nbsp; Ngram = n + 1<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Else</span><br />
&nbsp; &nbsp; &nbsp; qgs = Split(s, <span style="color: #800000;">&quot; &quot;</span>, , vbBinaryCompare)<br />
&nbsp; &nbsp; &nbsp; Ngram = <span style="color: #151B8D; font-weight: bold;">UBound</span>(qgs) + 1<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></div></div>
<p>&nbsp;<br />
La fonction principale :</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:400px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #E56717; font-weight: bold;">Public</span> <span style="color: #E56717; font-weight: bold;">Function</span> IndiceSimilarite(<span style="color: #151B8D; font-weight: bold;">ByVal</span> s1 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span>, <span style="color: #151B8D; font-weight: bold;">ByVal</span> s2 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span>, _<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> Indice <span style="color: #151B8D; font-weight: bold;">As</span> eIndiceSimilarite = eIndiceSimilarite.eDice, _<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> TypeNgram <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span> = 1, _<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> InversionGram <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Boolean</span> = <span style="color: #00C2FF; font-weight: bold;">False</span>, _<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> MaxDistance <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span> = -1, _<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Optional</span> <span style="color: #151B8D; font-weight: bold;">ByVal</span> TypeComparaison <span style="color: #151B8D; font-weight: bold;">As</span> VbCompareMethod = vbBinaryCompare) <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Single</span><br />
<span style="color: #008000;">'Retourne un indice de similarité [0 à 1] entre deux phrases<br />
</span><span style="color: #008000;">'Options : Indice : Choix de l'indice calculé (Cosinus, Dice, Jaccard, Kulczynski, BraunBlanquet)<br />
</span><span style="color: #008000;">' &nbsp; &nbsp; &nbsp; &nbsp;: TypeNgram : longueur des sous-séquences (0 : mot, 1 = caractère,...,5)<br />
</span><span style="color: #008000;">' &nbsp; &nbsp; &nbsp; &nbsp;: InversionGram : Recherche une inversion du gram :'ch' -&gt; 'hc' (sauf pour TypeNgram = 1 !)<br />
</span><span style="color: #008000;">' &nbsp; &nbsp; &nbsp; &nbsp;: MaxDistance : distance maximum (en gram) de recherche (-1 = pas de limite)<br />
</span><span style="color: #008000;">' &nbsp; &nbsp; &nbsp; &nbsp;: TypeComparaison : binaire ou textuelle<br />
</span><span style="color: #008000;">'Remarque: parfois nécessaire de prétraiter les chaînes (ucase(),trim(),sans diacritique,...)<br />
</span><span style="color: #008000;">'Auteur : Philben - v1.0 - Free to use<br />
</span><br />
&nbsp; &nbsp;Const cMaxLen <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span> = 256&amp;, cMinNgram <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span> = 0, cMaxNgram <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span> = 5<br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> l1 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, l2 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, i <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, j <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, jMin <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, jMax <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span><br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> c <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, n <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, n1 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, n2 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span><br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> aq1() <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span>, aq2() <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span>, q1 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span>, q1Inv <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span>, Idx <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Single</span>, Res <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Boolean</span><br />
<br />
&nbsp; &nbsp;l1 = Len(s1): l2 = Len(s2)<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> l1 &gt;= 1 <span style="color: #8D38C9; font-weight: bold;">And</span> l2 &gt;= 1 <span style="color: #8D38C9; font-weight: bold;">And</span> l1 &lt;= cMaxLen <span style="color: #8D38C9; font-weight: bold;">And</span> l2 &lt;= cMaxLen <span style="color: #8D38C9; font-weight: bold;">And</span> TypeNgram &gt;= cMinNgram <span style="color: #8D38C9; font-weight: bold;">And</span> TypeNgram &lt;= cMaxNgram <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> TypeNgram = 1 <span style="color: #8D38C9; font-weight: bold;">And</span> InversionGram <span style="color: #8D38C9; font-weight: bold;">Then</span> InversionGram = <span style="color: #00C2FF; font-weight: bold;">False</span><br />
<br />
&nbsp; &nbsp; &nbsp; n1 = Ngram(aq1, s1, TypeNgram, InversionGram)<br />
&nbsp; &nbsp; &nbsp; n2 = Ngram(aq2, s2, TypeNgram, InversionGram)<br />
&nbsp; &nbsp; &nbsp; n = n2 - 1<br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">For</span> i = 0 <span style="color: #8D38C9; font-weight: bold;">To</span> n1 - 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;q1 = aq1(i)<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> InversionGram <span style="color: #8D38C9; font-weight: bold;">Then</span> q1Inv = StrReverse(q1)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;jMin = 0: jMax = n<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> MaxDistance &gt; -1 <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> i &gt; MaxDistance <span style="color: #8D38C9; font-weight: bold;">Then</span> jMin = i - MaxDistance<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> jMax &gt; i + MaxDistance <span style="color: #8D38C9; font-weight: bold;">Then</span> jMax = i + MaxDistance<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">For</span> j = jMin <span style="color: #8D38C9; font-weight: bold;">To</span> jMax<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> aq2(j) &lt;&gt; vbNullString <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Res = (StrComp(q1, aq2(j), TypeComparaison) = 0)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> <span style="color: #8D38C9; font-weight: bold;">Not</span> Res <span style="color: #8D38C9; font-weight: bold;">And</span> InversionGram <span style="color: #8D38C9; font-weight: bold;">Then</span> Res = (StrComp(q1Inv, aq2(j), TypeComparaison) = 0)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> Res <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; c = c + 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; aq2(j) = vbNullString<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #E56717; font-weight: bold;">Exit</span> <span style="color: #8D38C9; font-weight: bold;">For</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Next</span> j<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Next</span> i<br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Select</span> <span style="color: #8D38C9; font-weight: bold;">Case</span> Indice<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Case</span> eCosinus &nbsp; <span style="color: #008000;">'Ochiai, Otsuka<br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; Idx = c / Sqr(CLng(n1) * n2) &nbsp; <span style="color: #008000;">'Cast pour éviter un overflow<br />
</span> &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Case</span> eDice &nbsp; <span style="color: #008000;">'Pirlot's index, Sorensen, Tversky (alpha=beta=0.5), ~Czekanowski<br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; Idx = 2 * c / (n1 + n2)<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Case</span> eJaccard &nbsp; <span style="color: #008000;">'Tversky (alpha=beta=1), ~Tanimoto<br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; Idx = c / (n1 + n2 - c)<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Case</span> eKulczynski &nbsp; <span style="color: #008000;">'2nd coeff<br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; Idx = 0.5 * (c / n1 + c / n2)<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Case</span> eBraunBlanquet &nbsp; <span style="color: #008000;">'c/max(n1,n2)<br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> n1 &gt;= n2 <span style="color: #8D38C9; font-weight: bold;">Then</span> Idx = c / n1 <span style="color: #8D38C9; font-weight: bold;">Else</span> Idx = c / n2<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Case</span> eSimpson &nbsp; <span style="color: #008000;">'c/min(n1,n2)<br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> n1 &lt;= n2 <span style="color: #8D38C9; font-weight: bold;">Then</span> Idx = c / n1 <span style="color: #8D38C9; font-weight: bold;">Else</span> Idx = c / n2<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">Select</span><br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Else</span><br />
&nbsp; &nbsp; &nbsp; Idx = -1<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
&nbsp; &nbsp;IndiceSimilarite = Idx<br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></div></div>
<p>&nbsp;<br />
<strong>Définition</strong><br />
Un gramme (ou gram en anglais) est une sous-séquences continues de caractères de la chaîne.<br />
&nbsp;<br />
<strong>Explications</strong><br />
Cette fonction ne mesure pas une distance entre les deux chaînes, elle compte seulement les grammes communs entre les deux chaînes S1 et S2.  Ce compte est ensuite divisé par un coefficient qui distingue les indices entre eux : Ce dénominateur peut être la moyenne géométrique du nombre de n-grams (n1 et n2), la moyenne arithmétique, le nombre maxi, mini&#8230;<br />
Le choix des indices est :</p>
<ul>
<li>Cosinus (équivalence : coefficients de Ochiai et de Otsuka)</li>
<li>Dice (équivalence : Pirlot&rsquo;s index, Sorensen, Tversky (alpha=beta=0.5), ~Czekanowski)</li>
<li>Jaccard (équivalence : Tversky (alpha=beta=1), ~Tanimoto)</li>
<li>Kulczynski (son second coefficient)</li>
<li>Braun-Blanquet (dénominateur : max(n1,n2))</li>
<li>Simpson (dénominateur : min(n1,n2))</li>
</ul>
<p>Si le nombre de n-grams est identique entre les deux chaînes, les indices retournent la même valeur mis à part l&rsquo;index de Jaccard. Par défaut le coefficient de Dice est utilisé.</p>
<p>La longueur des sous-séquences (paramètre <strong>TypeNgram</strong>) peut varier entre 0 et 5. Zéro indique qu&rsquo;un n-gramme correspond à un mot, 1-gramme ou unigramme correspond à chaque caractère de la chaîne, 2-gramme ou bigramme est composé de deux caractères, jusqu&rsquo;à 5-grammes. Au-dessus de 5-grammes la Prévention Informatique ne conseille pas de prendre le clavier !<br />
Par exemple, les bigrammes de &lsquo;abc&rsquo; seront &lsquo;%a&rsquo;, &lsquo;ab&rsquo;, &lsquo;bc&rsquo; et &lsquo;c#&rsquo; avec % et # des caractères non utilisés.</p>
<p>Le paramètre suivant (<strong>InversionGram</strong>) autorise ou non de compter un gramme inversé. Par exemple, &lsquo;ab&rsquo; et &lsquo;ba&rsquo; seront communs si InversionGram = True.</p>
<p>Le paramètre <strong>MaxDistance</strong> définit ou non une distance maximale (en valeur absolue) entre deux grammes communs. Si deux grammes communs sont trop éloignés, ils ne seront pas comptabilisés. Par exemple, la similarité calculée est égale à 0 si les chaînes sont &lsquo;ab&rsquo; et &lsquo;ba&rsquo; avec n-gram=1 et une distance maxi de zéro. Aucune limite de distance n&rsquo;est définie si MaxDistance = -1.</p>
<p>Enfin, le dernier paramètre définit le type de comparaison entre les deux chaînes (binaire ou textuelle).</p>
<p>Ces indices et celui de Damerau-Levenshtein n&rsquo;ont pas une réelle corrélation car ils ne mesurent pas la même chose.</p>
<p><strong>Exemples</strong><br />
Des anagrammes qui retournent un indice de similarité parfait (1) :</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">?IndiceSimilarite(<span style="color: #800000;">&quot;la crise economique&quot;</span>,<span style="color: #800000;">&quot;le scenario comique&quot;</span>)<br />
?IndiceSimilarite(<span style="color: #800000;">&quot;mammifere&quot;</span>,<span style="color: #800000;">&quot;mari femme&quot;</span>,eIndiceSimilarite.eSimpson)<br />
?IndiceSimilarite(<span style="color: #800000;">&quot;pascal obispo&quot;</span>,<span style="color: #800000;">&quot;pablo picasso&quot;</span>)<br />
?IndiceSimilarite(<span style="color: #800000;">&quot;stromae&quot;</span>,<span style="color: #800000;">&quot;maestro&quot;</span>)</div></div>
<p>Dans le deuxième exemple, on utilise l&rsquo;indice de Simpson car il divise le nombre de grammes communs par le plus petit nombre de n-grams entre n1 et n2 ce qui permet d&rsquo;obtenir un indice égal à 1.<br />
&nbsp;<br />
Via une requête SQL, une recherche d&rsquo;anagrammes sur des mots de 12 lettres dans une table a donné (après suppression des accents) :</p>
<div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Tactiquement Acquittement<br />
Conversation Conservation<br />
Premierement Empierrement<br />
Horticulture Horticulteur<br />
Resurrection Reconstruire<br />
Ternissement Ressentiment<br />
Egalisatrice Eclairagiste<br />
Photogravure Photograveur</div></div>
<p>&nbsp;<br />
Si on reprend l&rsquo;exemple de &lsquo;pascal obispo&rsquo; mais avec des bigrammes, l&rsquo;indice tombe à 0,36 et remonte à 0,43 si on autorise les inversions car &lsquo;&#8230; o&#8230;&rsquo; est commun à &lsquo;&#8230;o &#8230;&rsquo; de &lsquo;Pablo Picasso&rsquo;. L&rsquo;indice chute à 0,2 avec des trigrammes.</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">?IndiceSimilarite(<span style="color: #800000;">&quot;pascal obispo&quot;</span>,<span style="color: #800000;">&quot;pablo picasso&quot;</span>,,2)<br />
?IndiceSimilarite(<span style="color: #800000;">&quot;pascal obispo&quot;</span>,<span style="color: #800000;">&quot;pablo picasso&quot;</span>,,2,<span style="color: #00C2FF; font-weight: bold;">True</span>)<br />
?IndiceSimilarite(<span style="color: #800000;">&quot;pascal obispo&quot;</span>,<span style="color: #800000;">&quot;pablo picasso&quot;</span>,,3,<span style="color: #00C2FF; font-weight: bold;">True</span>)</div></div>
<p>On peut aussi jouer sur la distance maxi pour modifier sensiblement le résultat :</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">?IndiceSimilarite(<span style="color: #800000;">&quot;rehcehcre&quot;</span>,<span style="color: #800000;">&quot;recherche&quot;</span>) <span style="color: #008000;">'1<br />
</span>?IndiceSimilarite(<span style="color: #800000;">&quot;rehcehcre&quot;</span>,<span style="color: #800000;">&quot;recherche&quot;</span>,,,,2) <span style="color: #008000;">'1<br />
</span>?IndiceSimilarite(<span style="color: #800000;">&quot;rehcehcre&quot;</span>,<span style="color: #800000;">&quot;recherche&quot;</span>,,,,1) <span style="color: #008000;">'0,78<br />
</span>?IndiceSimilarite(<span style="color: #800000;">&quot;rehcehcre&quot;</span>,<span style="color: #800000;">&quot;recherche&quot;</span>,,,,0) <span style="color: #008000;">'0,56<br />
</span>?IndiceSimilarite(<span style="color: #800000;">&quot;rehcehcre&quot;</span>,<span style="color: #800000;">&quot;recherche&quot;</span>,,2,<span style="color: #00C2FF; font-weight: bold;">True</span>) <span style="color: #008000;">'1<br />
</span>?IndiceSimilarite(<span style="color: #800000;">&quot;rehcehcre&quot;</span>,<span style="color: #800000;">&quot;recherche&quot;</span>,,2,<span style="color: #00C2FF; font-weight: bold;">False</span>) <span style="color: #008000;">'0,3<br />
</span>?IndiceSimilarite(<span style="color: #800000;">&quot;rehcehcre&quot;</span>,<span style="color: #800000;">&quot;recherche&quot;</span>,,2,<span style="color: #00C2FF; font-weight: bold;">True</span>,2) <span style="color: #008000;">'0,8<br />
</span>?IndiceSimilarite(<span style="color: #800000;">&quot;rehcehcre&quot;</span>,<span style="color: #800000;">&quot;recherche&quot;</span>,,2,<span style="color: #00C2FF; font-weight: bold;">True</span>,0) <span style="color: #008000;">'0,4<br />
</span>?IndiceSimilarite(<span style="color: #800000;">&quot;rehcehcre&quot;</span>,<span style="color: #800000;">&quot;recherche&quot;</span>,,3,<span style="color: #00C2FF; font-weight: bold;">True</span>,0) '0,36</div></div>
<p>&nbsp;<br />
<strong>Performance</strong><br />
Cette fonction semble être 5 à 6 fois plus rapide que la fonction de Damerau-Levenshtein. Le principe mis en jeu est différent et les différentes possibilités de réglages permettent d&rsquo;adapter l&rsquo;algorithme à de nombreux cas de figures.</p>
<p>Voir aussi le billet sur la <a href="http://blog.developpez.com/philben/p12207/vba-access/vba-distance-de-jaro-winkler" title="VBA : Distance de Jaro-Winkler" target="_blank">distance de Jaro-Winkler</a>.</p>
<p>@+</p>
<p>Philippe</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Similarité entre deux chaînes de caractères</title>
		<link>https://blog.developpez.com/philben/p11268/vba-access/similarite_entre_deux_chaines_de_caracte</link>
		<comments>https://blog.developpez.com/philben/p11268/vba-access/similarite_entre_deux_chaines_de_caracte#comments</comments>
		<pubDate>Fri, 31 Aug 2012 16:06:49 +0000</pubDate>
		<dc:creator><![CDATA[philben]]></dc:creator>
				<category><![CDATA[SQL - Ms Access]]></category>
		<category><![CDATA[VBA - Ms Access]]></category>
		<category><![CDATA[Algorithme]]></category>
		<category><![CDATA[Chaîne de caractères]]></category>
		<category><![CDATA[Code VBA]]></category>
		<category><![CDATA[Similarité]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Pour tenter de réduire l&#8217;imperfection des ITCC, IPCC, ITPCC voire ITPCCC et plus généralement ICC(*), de nombreux algorithmes sont proposés (Soundex, Jaro-Winkler, &#8230;) et l&#8217;algorithme de Damerau-Levenshtein que j&#8217;ai implémenté ici en VBA. Voir aussi le billet sur les indices &#8230; <a href="https://blog.developpez.com/philben/p11268/vba-access/similarite_entre_deux_chaines_de_caracte">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Pour tenter de réduire l&rsquo;imperfection des ITCC, IPCC, ITPCC voire ITPCCC et plus généralement ICC(<strong>*</strong>), de nombreux algorithmes sont proposés (Soundex, Jaro-Winkler, &#8230;) et l&rsquo;algorithme de Damerau-Levenshtein que j&rsquo;ai implémenté ici en VBA.<br />
Voir aussi le billet sur les <a href="http://blog.developpez.com/philben/p11340/vba-access/indices-de-similarite-entre-deux-chaines-de-caracteres" title="Indices de similarité entre deux chaînes de caractères" target="_blank">indices de similarité</a> et le billet sur la <a href="http://blog.developpez.com/philben/p12207/vba-access/vba-distance-de-jaro-winkler" title="VBA : Distance de Jaro-Winkler" target="_blank">distance de Jaro-Winkler</a>.<br />
<span id="more-19"></span><br />
<strong>Le code source</strong></p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:400px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #E56717; font-weight: bold;">Public</span> <span style="color: #E56717; font-weight: bold;">Function</span> DamerauLevenshteinSimilarite(<span style="color: #151B8D; font-weight: bold;">ByVal</span> s1 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span>, <span style="color: #151B8D; font-weight: bold;">ByVal</span> s2 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">String</span>) <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Single</span><br />
<span style="color: #008000;">'Calcul la similarité (de [0 à 1]) entre deux chaines d'après l'algorithme de Damerau-Levenshtein<br />
</span><span style="color: #008000;">'références : http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance<br />
</span><span style="color: #008000;">' &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; http://mwh.geek.nz/2009/04/26/python-damerau-levenshtein-distance/<br />
</span><span style="color: #008000;">' &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; http://www-igm.univ-mlv.fr/~lecroq/seqcomp/node2.html<br />
</span><span style="color: #008000;">'Remarques &nbsp;: Préparer les chaines car les comparaisons sont binaires : UCase(), Trim(),...<br />
</span><span style="color: #008000;">'Philben v1.0 - Free to Use<br />
</span> &nbsp; Const cFacteur <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span> = &amp;H100&amp;, cMaxLen <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span> = 256&amp; &nbsp; <span style="color: #008000;">'Longueur maxi autorisée des chaines analysées<br />
</span> &nbsp; <span style="color: #151B8D; font-weight: bold;">Dim</span> l1 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, l2 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, c1 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span>, c2 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span><br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> r() <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, rp() <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, rpp() <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, i <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, j <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span><br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> c <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, x <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, y <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, z <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, f1 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, f2 <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span><br />
&nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">Dim</span> dls <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Single</span>, ac1() <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Byte</span>, ac2() <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Byte</span><br />
<br />
&nbsp; &nbsp;l1 = Len(s1): l2 = Len(s2)<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> l1 &gt; 0 <span style="color: #8D38C9; font-weight: bold;">And</span> l1 &lt;= cMaxLen <span style="color: #8D38C9; font-weight: bold;">And</span> l2 &gt; 0 <span style="color: #8D38C9; font-weight: bold;">And</span> l2 &lt;= cMaxLen <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; ac1 = s1: ac2 = s2 &nbsp; <span style="color: #008000;">'conversion des chaines en tableaux de bytes<br />
</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #008000;">'Initialise la ligne précédente (rp) de la matrice<br />
</span> &nbsp; &nbsp; &nbsp;<span style="color: #151B8D; font-weight: bold;">ReDim</span> rp(0 <span style="color: #8D38C9; font-weight: bold;">To</span> l2)<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">For</span> i = 0 <span style="color: #8D38C9; font-weight: bold;">To</span> l2: rp(i) = i: <span style="color: #8D38C9; font-weight: bold;">Next</span> i<br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">For</span> i = 1 <span style="color: #8D38C9; font-weight: bold;">To</span> l1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #008000;">'Initialise la ligne courante de la matrice<br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">ReDim</span> r(0 <span style="color: #8D38C9; font-weight: bold;">To</span> l2): r(0) = i<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #008000;">'Calcul le CharCode du caractère courant de la chaine<br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; f1 = (i - 1) * 2: c1 = ac1(f1 + 1) * cFacteur + ac1(f1)<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">For</span> j = 1 <span style="color: #8D38C9; font-weight: bold;">To</span> l2<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; f2 = (j - 1) * 2: c2 = ac2(f2 + 1) * cFacteur + ac2(f2)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; c = -(c1 &lt;&gt; c2) &nbsp; <span style="color: #008000;">'Cout : True = -1 =&gt; c = 1<br />
</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">'suppression, insertion, substitution<br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;x = rp(j) + 1: y = r(j - 1) + 1: z = rp(j - 1) + c<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> x &lt; y <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> x &lt; z <span style="color: #8D38C9; font-weight: bold;">Then</span> r(j) = x <span style="color: #8D38C9; font-weight: bold;">Else</span> r(j) = z<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> y &lt; z <span style="color: #8D38C9; font-weight: bold;">Then</span> r(j) = y <span style="color: #8D38C9; font-weight: bold;">Else</span> r(j) = z<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">'transposition<br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> i &gt; 1 <span style="color: #8D38C9; font-weight: bold;">And</span> j &gt; 1 <span style="color: #8D38C9; font-weight: bold;">And</span> c = 1 <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> c1 = ac2(f2 - 1) * cFacteur + ac2(f2 - 2) <span style="color: #8D38C9; font-weight: bold;">And</span> c2 = ac1(f1 - 1) * cFacteur + ac1(f1 - 2) <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> r(j) &gt; rpp(j - 2) + c <span style="color: #8D38C9; font-weight: bold;">Then</span> r(j) = rpp(j - 2) + c<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">Next</span> j<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #008000;">'Reculer d'un niveau la ligne précédente (rp) et courante (r)<br />
</span> &nbsp; &nbsp; &nbsp; &nbsp; rpp = rp: rp = r<br />
&nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Next</span> i<br />
&nbsp; &nbsp; &nbsp; <span style="color: #008000;">'Calcul la similarité via la distance entre les chaines r(l2)<br />
</span> &nbsp; &nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">If</span> l1 &gt;= l2 <span style="color: #8D38C9; font-weight: bold;">Then</span> dls = 1 - r(l2) / l1 <span style="color: #8D38C9; font-weight: bold;">Else</span> dls = 1 - r(l2) / l2<br />
&nbsp; &nbsp;<span style="color: #8D38C9; font-weight: bold;">ElseIf</span> l1 &gt; cMaxLen <span style="color: #8D38C9; font-weight: bold;">Or</span> l2 &gt; cMaxLen <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; dls = -1 &nbsp; <span style="color: #008000;">'indique un dépassement de longueur de chaine<br />
</span> &nbsp; <span style="color: #8D38C9; font-weight: bold;">ElseIf</span> l1 = 0 <span style="color: #8D38C9; font-weight: bold;">And</span> l2 = 0 <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; dls = 1 &nbsp; <span style="color: #008000;">'cas particulier<br />
</span> &nbsp; <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
<br />
&nbsp; &nbsp;DamerauLevenshteinSimilarite = dls<br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></div></div>
<p>&nbsp;<br />
<strong>Explications</strong><br />
L&rsquo;algorithme de Levenshtein mesure la distance entre deux chaînes de caractères qui est basée sur le nombre minimal de suppressions/insertions/substitutions de caractères pour passer d&rsquo;une chaîne à l&rsquo;autre.<br />
L&rsquo;algorithme de Damerau-Levenshtein ajoute en plus la <strong>transposition</strong> bien connue des dyslexiques du clavier (&lsquo;rehcerhce&rsquo; au lieu de &lsquo;recherche&rsquo;)&#8230;</p>
<p>Mon implémentation ne retourne pas une distance mais un indice de similarité allant de 0 à 1. La valeur 1 indique une similarité maximale entre deux chaînes. De plus, elle réalise une comparaison binaire des caractères, d&rsquo;où parfois la nécessité de prétraiter les chaînes (UCase(), Trim(), sans accent,&#8230;)</p>
<p>La complexité de l&rsquo;algorithme est O(m*n) avec m et n la longueur des chaînes ce qui limite son usage à des chaînes relativement courtes, des mots.<br />
&nbsp;<br />
<strong>Exemples</strong><br />
On peut utiliser cette fonction dans une requête SQL pour rechercher des doublons sur une petite(!) base de données en se basant sur une ou des colonnes (nom/prénom/adresse/&#8230;) ou afficher les données les plus similaires à une chaîne de recherche.</p>
<p>Par exemple, mon doigt a rippé par deux fois sur mon clavier AZERTY et j&rsquo;ai enchaîné un redressement un peu tardif qui a eu pour résultat : <strong>&lsquo;tbalrette&rsquo;</strong></p>
<p>La recherche de similarité dans une table de synonymes (+ de 36 000 entrées) a affiché :</p>
<ul>
<li>barette (0,78)</li>
<li>tablette (0,78)</li>
<li>turlurette (0,70)</li>
<li>targette (0,67)</li>
<li>&#8230;</li>
</ul>
<p>Je voulais écrire <strong>&lsquo;tablette&rsquo;</strong>.</p>
<p>Comme d&rsquo;habitude, vous pouvez tester la fonction dans la fenêtre Exécution du VBE :</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">?DamerauLevenshteinSimilarite(<span style="color: #800000;">&quot;tbalrette&quot;</span>,<span style="color: #800000;">&quot;tablette&quot;</span>) <span style="color: #008000;">'=&gt;0,7777778 <br />
</span>?DamerauLevenshteinSimilarite(<span style="color: #800000;">&quot;apple&quot;</span>,<span style="color: #800000;">&quot;appel&quot;</span>) <span style="color: #008000;">'=&gt;0,8 <br />
</span>?DamerauLevenshteinSimilarite(<span style="color: #800000;">&quot;chrizantème&quot;</span>,<span style="color: #800000;">&quot;chrysanthème&quot;</span>) <span style="color: #008000;">'=&gt;0,75 <br />
</span>?DamerauLevenshteinSimilarite(<span style="color: #800000;">&quot;rehcerche&quot;</span>,<span style="color: #800000;">&quot;recherche&quot;</span>) <span style="color: #008000;">'=&gt;0,8888889 <br />
</span>?DamerauLevenshteinSimilarite(<span style="color: #800000;">&quot;dnas&quot;</span>,<span style="color: #800000;">&quot;dans&quot;</span>) <span style="color: #008000;">'=&gt;0,75 <br />
</span>?DamerauLevenshteinSimilarite(<span style="color: #800000;">&quot;machine&quot;</span>,<span style="color: #800000;">&quot;appareil&quot;</span>) <span style="color: #008000;">'=&gt;0,125 <br />
</span>?DamerauLevenshteinSimilarite(<span style="color: #800000;">&quot;le jour se lève&quot;</span>,<span style="color: #800000;">&quot;le jour se couche&quot;</span>) '=&gt;0,7058824</div></div>
<p>&nbsp;<br />
<strong>(*)</strong></p>
<ul>
<li>ICC : Interface Chaise-Clavier</li>
<li>ITCC : Interface Téléphone-Chaise-Clavier</li>
<li>IPCC : Interface Papier-Chaise-Clavier</li>
<li>ITPCC : Interface Téléphone-Papier-Chaise-Clavier</li>
<li>ITPCCC : Interface Téléphone-Papier-Collègue-Chaise-Clavier</li>
</ul>
<p>Pour en savoir plus sur le <a href="http://en.wikipedia.org/wiki/User_error">thème</a> <em>errare humanum est</em>&#8230;</p>
<p>@+</p>
<p>Philippe</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
