source: spip-zone/_core_/plugins/grenier/inc/ressembler.php

Last change on this file was 119511, checked in by spip.franck@…, 16 months ago

Bonne année "grenier"

File size: 3.6 KB
Line 
1<?php
2
3/***************************************************************************\
4 *  SPIP, Systeme de publication pour l'internet                           *
5 *                                                                         *
6 *  Copyright (c) 2001-2020                                                *
7 *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
8 *                                                                         *
9 *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
10 *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
11\***************************************************************************/
12
13
14if (!defined('_ECRIRE_INC_VERSION')) return;
15
16
17
18/**
19 * Calcule une distance levenshtein
20 * (similarité entre 2 chaines)
21 * en ne prenant en compte que les 254 premiers
22 * caractères des chaines transmises.
23 *
24 * [ne pas faire d'erreur si les chaines sont > 254 caracteres]
25 *
26 * @param string $a     premier mot
27 * @param string $b     second mot
28 * @return distance de levenshtein
29**/
30// https://code.spip.net/@levenshtein255
31function levenshtein255($a, $b) {
32        $a = substr($a, 0, 254);
33        $b = substr($b, 0, 254);
34        return @levenshtein($a, $b);
35}
36
37
38/**
39  * Reduit un mot a sa valeur translitteree et en minuscules
40  *
41  * @param string $mot Mot a transliterer
42  * @return Mot translittere en minuscule.
43 **/
44// https://code.spip.net/@reduire_mot
45function reduire_mot($mot) {
46        return strtr(
47                translitteration(trim($mot)),
48                'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
49                'abcdefghijklmnopqrstuvwxyz'
50                );
51}
52
53
54/**
55 * Retrouve dans une liste donnee les mots qui ont des orthographes
56 * proches d'un certain mot.
57 * L'algorythme utilise la distance de levenshtein, pour trouver ces mots
58 * et retourne les identifiants de table correspondants dans second tableau transmis.
59 *
60 * @param string $mot   Le mot a chercher : 'juniur'
61 * @param array $table_mots             Le dictionnaire : array('junior', 'vivien')
62 * @param array $table_ids              Optionnel, table d'identifiants correspondants : array(3, 5)
63 * @return array        Liste des noms (ou identifiants si transmis) approchants : array('junior') ou array(3)
64**/
65// https://code.spip.net/@mots_ressemblants
66function mots_ressemblants($mot, $table_mots, $table_ids = '') {
67
68        $result = array();
69
70        if (!$table_mots) return $result;
71
72        $lim = 2;
73        $nb = 0;
74        $opt = 1000000;
75        $mot_opt = '';
76        $mot = reduire_mot($mot);
77        $len = strlen($mot);
78
79        while (!$nb and $lim < 10) {
80                reset($table_mots);
81                if ($table_ids) reset($table_ids);
82                while (list(, $val) = each($table_mots)) {
83                        if ($table_ids) list(, $id) = each($table_ids);
84                        else $id = $val;
85                        $val2 = trim($val);
86                        if ($val2) {
87                                if (!isset($distance[$id])) {
88                                        $val2 = reduire_mot($val2);
89                                        $len2 = strlen($val2);
90                                        if ($val2 == $mot)
91                                                $m = -2; # resultat exact
92                                        elseif (substr($val2, 0, $len) == $mot)
93                                                $m = -1; # sous-chaine
94                                        else {
95                                                # distance
96                                                $m = levenshtein255($val2, $mot);
97                                                # ne pas compter la distance due a la longueur
98                                                $m -= max(0, $len2 - $len);
99                                        }
100                                        $distance[$id] = $m;
101                                } else $m = 0;
102                                if ($m <= $lim) {
103                                        $selection[$id] = $m;
104                                        if ($m < $opt) {
105                                                $opt = $m;
106                                                $mot_opt = $val;
107                                        }
108                                        $nb++;
109                                }
110                        }
111                }
112                $lim += 2;
113        }
114
115        if (!$nb) return $result;
116        reset($selection);
117        if ($opt > -1) {
118                $moy = 1;
119                while(list(, $val) = each($selection)) $moy *= $val;
120                if($moy) $moy = pow($moy, 1.0 / $nb);
121                $lim = ($opt + $moy) / 2;
122        }
123        else $lim = -1;
124
125        reset($selection);
126        while (list($key, $val) = each($selection)) {
127                if ($val <= $lim) {
128                        $result[] = $key;
129                }
130        }
131        return $result;
132}
Note: See TracBrowser for help on using the repository browser.