Autres la fonction similaire

patricktoulon

XLDnaute Barbatruc
Bonjour à tous et @Dudu2
j'ouvre cette discussion a fin de ne pas mettre le boxon dans une autre dans la quelle j'ai proposer la fonction similaire
en 2020/2021 je sais plus trop j'avais ajouté dans la fonction une partie gérant la présence de chaque mot de la chaine 1 dans la chaine 2
cela dit je me rend compte qu'elle peut être discriminatoire ou inversement me donner un 100%
alors que la chaine 2 est plus grande
certes la chaine2 contient tout les mots de la chaine 1 mais le pourcentage ne devrait pas être 100%
voici la fonction je n'en suis pas l'auteur à la base je l'ai juste arrangée a ma sauce

VB:
Public Function similaire(ByVal s1 As String, ByVal s2 As String) As Double
    Const cFacteur As Long = &H100&, cMaxLen As Long = 256& 'Longueur maxi autorisée des chaines analysées
    Dim l1 As Long, l2 As Long, c1 As Long, c2 As Long
    Dim r() As Integer, rp() As Integer, rpp() As Integer, i As Integer, j As Integer
    Dim c As Integer, x As Integer, y As Integer, z As Integer, f1 As Integer, f2 As Integer
    Dim dls As String, ac1() As Byte, ac2() As Byte
    Dim px As Double, p As Double, oz As Long
    Dim t1, t2
    '*****************************************************
    'analyse dans un ordre different
    If s1 = s2 Then similaire = 100: Exit Function

    t1 = Split(Replace(s1, "-", " "), " "): t2 = Split(Replace(s1, "-", " "), " ")
    If UBound(t2) > UBound(t1) Then tbl = t12: s2 = s1 Else tbl = t1
    If IsArray(tbl) Then
        If UBound(tbl) > 1 Then
            p = 100 / (UBound(tbl) + 1)
            For oz = 0 To UBound(tbl): px = px + IIf(" " & s2 & " " Like "* " & tbl(oz) & "* ", p, -p): Next
            If px = 100 Then similaire = 100: Exit Function
        End If
    End If

    '**************************************************
    'analyse binaire
    l1 = Len(s1): l2 = Len(s2)
    If l1 > 0 And l1 <= cMaxLen And l2 > 0 And l2 <= cMaxLen Then

        ac1 = s1 'conversion des chaines en tableaux de bytes
        ac2 = s2
        'Initialise la ligne précédente (rp) de la matrice
        ReDim rp(0 To l2)
        For i = 0 To l2: rp(i) = i: Next i
        For i = 1 To l1
            'Initialise la ligne courante de la matrice
            ReDim r(0 To l2): r(0) = i
            'Calcul le CharCode du caractère courant de la chaine
            f1 = (i - 1) * 2: c1 = ac1(f1 + 1) * cFacteur + ac1(f1)
            For j = 1 To l2
                f2 = (j - 1) * 2: c2 = ac2(f2 + 1) * cFacteur + ac2(f2)
                c = -(c1 <> c2) 'Cout : True = -1 => c = 1
                'suppression, insertion, substitution
                x = rp(j) + 1: y = r(j - 1) + 1: z = rp(j - 1) + c
                If x < y Then
                    If x < z Then r(j) = x Else r(j) = z
                Else
                    If y < z Then r(j) = y Else r(j) = z
                End If
                'transposition
                If i > 1 And j > 1 And c = 1 Then
                    If c1 = ac2(f2 - 1) * cFacteur + ac2(f2 - 2) And c2 = ac1(f1 - 1) * cFacteur + ac1(f1 - 2) Then
                        If r(j) > rpp(j - 2) + c Then r(j) = rpp(j - 2) + c
                    End If
                End If
            Next j
            'Reculer d'un niveau la ligne précédente (rp) et courante (r)
            rpp = rp: rp = r
        Next i
        'Calcul la similarité via la distance entre les chaines r(l2)
        If l1 >= l2 Then dls = 1 - r(l2) / l1 Else dls = 1 - r(l2) / l2
    ElseIf l1 > cMaxLen Or l2 > cMaxLen Then
        dls = -1 'indique un dépassement de longueur de chaine
    ElseIf l1 = 0 And l2 = 0 Then
        dls = 1 'cas particulier
    End If
    similaire = dls * 100
End Function

prenons un exemple de chaines à comparer
chaine1="titi toto"
chaine 2="titi toto"
msgbox similaire(chaine1,chaine2)
'la réponse va être sans appel c'est du 100% car on est sorti de la fonction par la partie unordered

maintenant si je met un pluriel
chaine1="titi toto"
chaine 2="titi totos"
msgbox similaire(chaine1,chaine2)
'la réponse va être sans appel c'est du 100%'car on est sorti de la fonction par la partie unordered
alors oui tout les mots de la chaine 1 se trouvent dans la chaine 2 mais elle ne sont pas egales
je cherche le moyen donc de garder la partie unordered mais quelle soit plus juste
j'ai donc dans un fichier vierge cherché un moyen que cette partie soit plus juste au résultat
j'ai donc écrit ce nouveau code pour tester
VB:
Function Ressemble(s1 As String, s2 As String)
    Dim T2, T1, TbL, x, px#, devaluation#
    s1 = Trim(s1): s2 = Trim(s2)
    s1 = Replace(s1, "-", " ")
    s2 = Replace(s2, "-", " ")
    '*****************************************************
    'analyse dans un ordre different(UNORDERED)
    If s1 = s2 Then Ressemble = 100: Exit Function

    T1 = Split(s1, " ")
    T2 = Split(s2, " ")
    x = WorksheetFunction.Max(UBound(T1), UBound(T2))
    y = WorksheetFunction.Min(UBound(T1), UBound(T2))
     devaluation = ((100 / x) * Abs(x - y)) / 2
    
     If UBound(T2) < UBound(T1) Then TbL = T2: s2 = s1 Else TbL = T1
    If IsArray(TbL) Then
        If UBound(TbL) > 1 Then
            p = 100 / (UBound(T1) + 1)
            For oz = 0 To UBound(TbL)
                If " " & s2 & " " Like "* " & TbL(oz) & " *" Then px = px + p
            Next
        End If
    End If
    
    'pour rendre la note equitable par rapport au nombre de mots supplémentaire
    If Val(px) = 100 Then px = px - devaluation
    

   Ressemble = px
End Function

  MsgBox Ressemble("les pommes du pays de galle", "les pommes du pays de galle")

    MsgBox Ressemble("les pommes du pays de galle", "les pommes vertes du pays de galle")
en fait j'ai un 100% si tout les mots sont présents dans n'importe quel ordre
et j'impute une devaluation en fonction du nombre de mots supplémentaires
dites moi ce que vous en pensez
pensez vous que ce soit rentable de l'intégrer dans la fonction similaire dans a la place de la partie unordered

avec peut être un switch ressemblance/similaire
Allez @Dudu2 au boulot ;) 😂
je joins un fichier
 

Pièces jointes

  • fonction similaire in remasters 2024 plus fonction ressenblance.xlsm
    22.2 KB · Affichages: 3

patricktoulon

XLDnaute Barbatruc
[hors sujet]
ouvre le faisceau si dispo dans l'emplacement batterie sinon il faudra faire un aller retour si tu veux absolument le placer dans la loge de la batterie
sur le typon de la boite fusible n'y a t il pas des emplacements non connectés et ou non utilisés
déjà tu a regardé?
[/hors sujet]
 

jurassic pork

XLDnaute Occasionnel
Hello,
Pour faire des calculs de similarité il y a l'algorithme de la distance de Levenshtein. Je ne sais pas si c'est cela que tu utilises Patrick ou un dérivé. En tout cas Il y a du code en VBA ici qui utilise cet algorithme pour faire un calcul de similarité de chaînes .
Exemple d'utilisation :
VB:
Sub Test_Similarity()
Debug.Print String_Similarity("toto titi", "toto titi")
Debug.Print String_Similarity("toto titi", "toto titis")
Debug.Print String_Similarity("toto titi", "totos titis")
End Sub

1
0,9
0,818181818181818

Ami calmant, J.P
 

patricktoulon

XLDnaute Barbatruc
Bonjour @jurassic pork
oui c'est bien l'algorithme de levenshtein
une version avec des dico je n'avais jamais vu ça
il semblerait que l'auteur ai séparé les opérations de substitution et insertion et inversion (les 3 costs)
par sur que la rapidité soit égale à la version que j'utilise mais si ça marche pourquoi pas

cela dit :c'est pas ça le sujet de la discussion en fait
c'est l'incorporation comme c'est le cas actuellement d'un pré traitement par mots et si c'est bon on ne passe pas l'algo sauf que je souhaite rendre plus pointu et plus juste la partie unordered (ressemblance)
 

patricktoulon

XLDnaute Barbatruc
je pense avoir trouvé un bon compromis pour la fonction ressemble
VB:
'*****************************************************************************************************
'    ___     _     _______  __      _   ____  _   _  _______  ___     _   _   _    ___     _     _.
'   //  \\  /\\      //    // \\   //  //    //  //    //    //  \\  //  //  //   //  \\  //|   //
'  //___// //__\    //    //__//  //  //    //__//    //    //   // //  //  //   //   // // |  //
' //      //   \\  //    //  \\  //  //    //  \\    //    //   // //  //  //   //   // //  | //
'//      //    // //    //   // //  //___ //    \\  //     \\__// //__//  //___ \\__// //   |//
'****************************************************************************************************
'Fonction pour mesurer la ressemblance entre deux chaines en terme de mots entiers
'Auteur:patricktoulon
'Version 2.0
'Date version: 29/10/2024
'---------------------------------------------------------------------------------------------------
Function Ressemble(s1 As String, s2 As String)
    Dim t2, t1, TbL, Tbl2, x, px#, devaluation#
    s1 = Trim(s1): s2 = Trim(s2)
    s1 = Replace(s1, "-", " ")
    s2 = Replace(s2, "-", " ")
    '*****************************************************
    'analyse dans un ordre different
    If s1 = s2 Then Ressemble = 100: Exit Function

    t1 = Split(s1, " ")
    t2 = Split(s2, " ")
    x = WorksheetFunction.Max(UBound(t1), UBound(t2))
    y = WorksheetFunction.Min(UBound(t1), UBound(t2))
    devaluation = ((100 / x) * Abs(x - y)) / 2

    If UBound(t2) < UBound(t1) Then TbL = t2: Tbl2 = t1: s2 = s1 Else TbL = t1: Tbl2 = t2
    If IsArray(TbL) Then
        If UBound(TbL) > 1 Then
            p = 100 / (UBound(t1) + 1)
            For oz = 0 To UBound(TbL)
                  ok = 0
                  For w = 0 To UBound(Tbl2)
                        If TbL(oz) = Tbl2(w) Then ok = 1
                        Next
               If ok = 1 Then
               px = px + p
               Else
                    For w = 0 To UBound(Tbl2)
                        If TbL(oz) Like "*" & Tbl2(w) & "*" Then px = px + (p / 2)
                    Next
                End If
            Next

        End If
    End If
    
    'pour rendre la note equitable par rapport au nombre de mots supplémentaire
    If Val(px) = 100 And devaluation > 0 Then px = px - devaluation

    Ressemble = px
End Function
Sub test()
les résultats dans la colonne B
on a bien la différence
entre un mot différent ou un mot au pluriel
on vois bien aussi par exemple qu'avec une chaine dans le désordre là ou similaire rejette la fonction ressemble elle le prend et à 100% quand l'orthographe est identique
1730216299976.png
 

patricktoulon

XLDnaute Barbatruc
re
Bonjour @Dudu2
en B le resultat de ressemblance
en D le resultat de similaire

on peut aisément constater que la même chose même orthographe mais dans un ordre différent va avoir un score très bas avec similaire alors que c'est du 100% dans un ordre différent avec ressemblance

on constate aussi que une faute ou une lettre au milieu d'un mot ou ala fin ne donnera pas le même résultat
il faut que je peaufine encore
mais je pense que les deux sont bien selon le besoin
 

Pièces jointes

  • fonction similaire in remasters 2024 plus fonction ressenblance.xlsm
    25.2 KB · Affichages: 1

Dudu2

XLDnaute Barbatruc
Ok merci.
Je remarque qu'il n'y a pas de traitement des caractères accentués.
Elodie va a l'ecole et Elodie va à l'école ne se ressemblent qu'à 50%.

C'est juste pour l'anglais qui n'a pas d'accents. Mais pour nous ou d'autres ?
Peut-être faudrait-il introduire une épuration des accents ?
Alors est-ce que ça devrait être 100% (soit -0% par accent) ou 95% (soit -2.5% par accent) ou 90% (soit -5% par accent) ? Ou un forfait de -10% quand il y a au moins 1 différence due aux accents ?
 
Dernière édition:

Dudu2

XLDnaute Barbatruc
Les majuscules aussi.
Elodie va a l'ecole et ELODIE VA A L'ECOLE ne se ressemblent qu'à 26,32 %
Là c'est moins grave car on peut "UCaser" ou "LCaser" les arguments, mais il faut le savoir que c'est une cause de non ressemblance.
 

Dudu2

XLDnaute Barbatruc
VB:
'-----------------------------------------------
'Épuration d'une chaine des caractères accentués
'-----------------------------------------------
Private Function ÉpurerChaine(Chaine As String) As String
    'Const LettresDiacritiques = "ÀÂÉÈÊÎÔÙÛÇàâéèêîôùûç"
    'Const LettresNormales = "AAEEEIOUUCaaeeeiouuc"
    Const LettresDiacritiques = "ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝŸàáâãäåçèéêëìíîïñòóôõöùúûüýÿ"
    Const LettresNormales = "AAAAAACEEEEIIIINOOOOOUUUUYYaaaaaaceeeeiiiinooooouuuuyy"
    Dim i As Integer
    Dim k As Integer
    Dim S As String
    
    S = Chaine
    
    For i = 1 To Len(S)
        k = InStr(LettresDiacritiques, Mid(S, i, 1))
        If k Then Mid(S, i, 1) = Mid(LettresNormales, k, 1)
    Next i
    
    ÉpurerChaine = S
End Function
 

patricktoulon

XLDnaute Barbatruc
Bonjour @Dudu2 et à tous
version 4 je vais un peu plus loin sur cette version V4 de la fonction ressemble
je teste tout en ucase
  1. la note en poucentage est séparée en 4
  2. nombres de mots dans s1 et s2
  3. nombre de mots identiques
  4. ordre des mots
  5. +recherche du presque mot
une énigme à trouver (je suis sensé tester deux chaines sans accents)
 

Pièces jointes

  • fonction similaire in remasters 2024 plus fonction ressenblance.xlsm
    33.5 KB · Affichages: 0

Discussions similaires

Réponses
7
Affichages
508

Statistiques des forums

Discussions
314 720
Messages
2 112 187
Membres
111 457
dernier inscrit
anglade