2012-06-15 18:29:24 +0000 2012-06-15 18:29:24 +0000
14
14

Comparaison de chaînes de texte similaires dans Excel

J'essaie actuellement de concilier les champs “Nom” de deux sources de données distinctes. J'ai un certain nombre de noms qui ne correspondent pas exactement mais qui sont suffisamment proches pour être considérés comme concordants (exemples ci-dessous). Avez-vous une idée de la manière dont je pourrais améliorer le nombre de correspondances automatisées ? Je suis déjà en train d'éliminer les initiales du milieu des critères de correspondance.

=IFERROR(IF(LEFT(SYSTEM A,IF(ISERROR(SEARCH(" ",SYSTEM A)),LEN(SYSTEM A),SEARCH(" ",SYSTEM A)-1))=LEFT(SYSTEM B,IF(ISERROR(SEARCH(" ",SYSTEM B)),LEN(SYSTEM B),SEARCH(" ",SYSTEM B)-1)),"",IF(LEFT(SYSTEM A,FIND(",",SYSTEM A))=LEFT(SYSTEM B,FIND(",",SYSTEM B)),"Last Name Match","RESEARCH")),"RESEARCH")

Formule de correspondance actuelle :

Réponses (7)

12
12
12
2012-06-15 18:51:25 +0000

Vous pourriez envisager d'utiliser l'addin Microsoft Fuzzy Lookup Addin .

du site MS :

Aperçu

Le complément Fuzzy Lookup Add-In pour Excel a été développé par Microsoft Research et permet d'effectuer une correspondance floue des données textuelles dans Microsoft Excel. Il peut être utilisé pour identifier des lignes dupliquées floues dans un tableau unique ou pour joindre de manière floue des lignes similaires entre deux tableaux différents. La mise en correspondance est robuste à une grande variété d'erreurs, y compris les fautes d'orthographe, les abréviations, les synonymes et les données ajoutées/manquantes. Par exemple, il peut détecter que les lignes “Mr. Andrew Hill”, “Hill, Andrew R.” et “Andy Hill” font toutes référence à la même entité sous-jacente, en renvoyant un score de similarité avec chaque correspondance. Si la configuration par défaut fonctionne bien pour une grande variété de données textuelles, telles que les noms de produits ou les adresses de clients, la correspondance peut également être personnalisée pour des domaines ou des langues spécifiques.

6
6
6
2012-06-15 19:47:53 +0000

J'envisagerais d'utiliser this list (section anglaise uniquement) pour aider à éliminer les raccourcissements courants.

Addition, vous pourriez envisager d'utiliser une fonction qui vous indiquera, en termes exacts, à quel point deux chaînes sont “proches”. Le code suivant provient de ici et grâce à smirkingman .

Option Explicit
Public Function Levenshtein(s1 As String, s2 As String)

Dim i As Integer
Dim j As Integer
Dim l1 As Integer
Dim l2 As Integer
Dim d() As Integer
Dim min1 As Integer
Dim min2 As Integer

l1 = Len(s1)
l2 = Len(s2)
ReDim d(l1, l2)
For i = 0 To l1
    d(i, 0) = i
Next
For j = 0 To l2
    d(0, j) = j
Next
For i = 1 To l1
    For j = 1 To l2
        If Mid(s1, i, 1) = Mid(s2, j, 1) Then
            d(i, j) = d(i - 1, j - 1)
        Else
            min1 = d(i - 1, j) + 1
            min2 = d(i, j - 1) + 1
            If min2 < min1 Then
                min1 = min2
            End If
            min2 = d(i - 1, j - 1) + 1
            If min2 < min1 Then
                min1 = min2
            End If
            d(i, j) = min1
        End If
    Next
Next
Levenshtein = d(l1, l2)
End Function

Ce qui vous indiquera combien d'insertions et de suppressions il faut faire sur une chaîne pour arriver à l'autre. J'essaierais de garder ce nombre bas (et les noms de famille devraient être exacts).

5
5
5
2015-10-09 14:26:12 +0000

J'ai une formule (longue) que vous pouvez utiliser. Elle n'est pas aussi précise que les précédentes - et ne fonctionne que pour le nom de famille, plutôt que pour le prénom - mais vous pourriez la trouver utile.

Donc si vous avez une ligne d'en-tête et que vous voulez comparer A2 avec B2, placez cette formule dans n'importe quelle autre cellule de cette ligne (par exemple, C2) et copiez jusqu'à la fin.

=IF(A2=B2, “EXACT”,IF(SUBSTITUTE(A2,“-”,“ ”)=SUBSTITUTE(B2,“-”,“ ”), “Hyphen”,IF(LEN(A2)>LEN(B2),IF(LEN(A2)>LEN(SUBSTITUTE(A2,B2,“”)), “Whole String”,IF(MID(A2,1, 1)=MID(B2,1,1),1,0)+IF(MID(A2,2,1)=MID(B2,2,1),1,0)+IF(MID(A2,3,1)=MID(B2,3,1),1,0)+IF(MID(A2,LEN(A2),1)=MID(B2,LEN(B2),1),1,0)+IF(MID(A2,LEN(A2)-1,1)=MID(B2,LEN(B2)-1,1),1, 0)+IF(MID(A2,LEN(A2)-2,1)=MID(B2,LEN(B2)-2,1),1,0)&“°”),IF(LEN(B2)>LEN(SUBSTITUTE(B2,A2,“”)), “Whole String”,IF(MID(A2,1,1)=MID(B2,1,1),1,0)+IF(MID(A2,2,1)=MID(B2,2,1),1, 0)+IF(MID(A2,3,1)=MID(B2,3,1),1,0)+IF(MID(A2,LEN(A2),1)=MID(B2,LEN(B2),1),1,0)+IF(MID(A2,LEN(A2)-1,1)=MID(B2,LEN(B2)-1,1),1,0)+IF(MID(A2,LEN(A2)-2,1)=MID(B2,LEN(B2)-2,1),1,0)&“°”))))

Cela reviendra :

  • EXACT - s'il s'agit d'une correspondance exacte
  • Hyphen - s'il s'agit d'une paire de noms à double barre mais sur a un trait d'union et l'autre un espace
  • Cordon entier - si tous les noms de famille font partie de l'autre (par exemple, si un Dupont est devenu un forgeron français)

Après cela, il vous donnera un degré de 0° à 6° selon le nombre de points de comparaison entre les deux. (c'est-à-dire que 6° se compare mieux).

Comme je l'ai dit, c'est un peu rude et prêt, mais j'espère que cela vous permettra de vous placer dans le bon camp.

2
2
2
2016-06-23 06:12:19 +0000

cherchait quelque chose de similaire. J'ai trouvé le code ci-dessous. J'espère que cela aidera le prochain utilisateur qui vient à cette question

Retourne 91% pour Abracadabra / Abrakadabra, 75% pour Hollywood Street/Hollyhood Str, 62% pour Florence/France et 0 pour Disneyland

Je dirais que c'est assez proche de ce que vous vouliez :)

Public Function Similarity(ByVal String1 As String, _
    ByVal String2 As String, _
    Optional ByRef RetMatch As String, _
    Optional min_match = 1) As Single
Dim b1() As Byte, b2() As Byte
Dim lngLen1 As Long, lngLen2 As Long
Dim lngResult As Long

If UCase(String1) = UCase(String2) Then
    Similarity = 1
Else:
    lngLen1 = Len(String1)
    lngLen2 = Len(String2)
    If (lngLen1 = 0) Or (lngLen2 = 0) Then
        Similarity = 0
    Else:
        b1() = StrConv(UCase(String1), vbFromUnicode)
        b2() = StrConv(UCase(String2), vbFromUnicode)
        lngResult = Similarity_sub(0, lngLen1 - 1, _
        0, lngLen2 - 1, _
        b1, b2, _
        String1, _
        RetMatch, _
        min_match)
        Erase b1
        Erase b2
        If lngLen1 >= lngLen2 Then
            Similarity = lngResult / lngLen1
        Else
            Similarity = lngResult / lngLen2
        End If
    End If
End If

End Function

Private Function Similarity_sub(ByVal start1 As Long, ByVal end1 As Long, _
                                ByVal start2 As Long, ByVal end2 As Long, _
                                ByRef b1() As Byte, ByRef b2() As Byte, _
                                ByVal FirstString As String, _
                                ByRef RetMatch As String, _
                                ByVal min_match As Long, _
                                Optional recur_level As Integer = 0) As Long
'* CALLED BY: Similarity *(RECURSIVE)

Dim lngCurr1 As Long, lngCurr2 As Long
Dim lngMatchAt1 As Long, lngMatchAt2 As Long
Dim I As Long
Dim lngLongestMatch As Long, lngLocalLongestMatch As Long
Dim strRetMatch1 As String, strRetMatch2 As String

If (start1 > end1) Or (start1 < 0) Or (end1 - start1 + 1 < min_match) _
Or (start2 > end2) Or (start2 < 0) Or (end2 - start2 + 1 < min_match) Then
    Exit Function '(exit if start/end is out of string, or length is too short)
End If

For lngCurr1 = start1 To end1
    For lngCurr2 = start2 To end2
        I = 0
        Do Until b1(lngCurr1 + I) <> b2(lngCurr2 + I)
            I = I + 1
            If I > lngLongestMatch Then
                lngMatchAt1 = lngCurr1
                lngMatchAt2 = lngCurr2
                lngLongestMatch = I
            End If
            If (lngCurr1 + I) > end1 Or (lngCurr2 + I) > end2 Then Exit Do
        Loop
    Next lngCurr2
Next lngCurr1

If lngLongestMatch < min_match Then Exit Function

lngLocalLongestMatch = lngLongestMatch
RetMatch = ""

lngLongestMatch = lngLongestMatch _
+ Similarity_sub(start1, lngMatchAt1 - 1, _
start2, lngMatchAt2 - 1, _
b1, b2, _
FirstString, _
strRetMatch1, _
min_match, _
recur_level + 1)
If strRetMatch1 <> "" Then
    RetMatch = RetMatch & strRetMatch1 & "*"
Else
    RetMatch = RetMatch & IIf(recur_level = 0 _
    And lngLocalLongestMatch > 0 _
    And (lngMatchAt1 > 1 Or lngMatchAt2 > 1) _
    , "*", "")
End If

RetMatch = RetMatch & Mid$(FirstString, lngMatchAt1 + 1, lngLocalLongestMatch)

lngLongestMatch = lngLongestMatch _
+ Similarity_sub(lngMatchAt1 + lngLocalLongestMatch, end1, _
lngMatchAt2 + lngLocalLongestMatch, end2, _
b1, b2, _
FirstString, _
strRetMatch2, _
min_match, _
recur_level + 1)

If strRetMatch2 <> "" Then
    RetMatch = RetMatch & "*" & strRetMatch2
Else
    RetMatch = RetMatch & IIf(recur_level = 0 _
    And lngLocalLongestMatch > 0 _
    And ((lngMatchAt1 + lngLocalLongestMatch < end1) _
    Or (lngMatchAt2 + lngLocalLongestMatch < end2)) _
    , "*", "")
End If

Similarity_sub = lngLongestMatch

End Function
1
1
1
2015-10-30 10:56:53 +0000

Ce code scanne la colonne a et la colonne b, s'il trouve une quelconque similitude dans les deux colonnes, il l'affiche en jaune. Vous pouvez utiliser un filtre de couleur pour obtenir la valeur finale. Je n'ai pas ajouté cette partie dans le code.

Sub item_difference()

Range("A1").Select

last_row_all = Range("A65536").End(xlUp).Row
last_row_new = Range("B65536").End(xlUp).Row

Range("A1:B" & last_row_new).Select
With Selection.Interior
    .Pattern = xlSolid
    .PatternColorIndex = xlAutomatic
    .Color = 65535
    .TintAndShade = 0
    .PatternTintAndShade = 0
End With

For i = 1 To last_row_new
For j = 1 To last_row_all

If Range("A" & i).Value = Range("A" & j).Value Then

Range("A" & i & ":B" & i).Select
With Selection.Interior
    .Pattern = xlSolid
    .PatternColorIndex = xlAutomatic
    .ThemeColor = xlThemeColorDark1
    .TintAndShade = 0
  .PatternTintAndShade = 0
End With

End If
Next j
Next i
End Sub
1
1
1
2016-09-14 12:14:05 +0000

Bien que ma solution ne permette pas d'identifier des chaînes très différentes, elle est utile pour les correspondances partielles (correspondance de sous-chaîne), par exemple “ceci est une chaîne” et “une chaîne” donnera comme résultat une “correspondance” :

ajoutez simplement “*” avant et après la chaîne à rechercher dans le tableau.

Formule habituelle :

  • vlookup(A1,B1:B10,1,0)
  • cerca.vert(A1;B1:B10;1;0)

devient

  • vlookup(“*” & A1 & “*”,B1:B10;1,0)
  • cerca. vert(“*” & A1 & “*”;B1:B10;1;0)

“&” est la “version courte” pour concatenate()

1
1
1
2015-02-05 02:42:16 +0000

Vous pouvez utiliser la fonction de similarité (pwrSIMILARITY) pour comparer les chaînes de caractères et obtenir un pourcentage de correspondance entre les deux. Vous pouvez respecter la casse ou non. Vous devrez décider quel pourcentage de correspondance est “assez proche” pour vos besoins.

Il existe une page de référence sur http://officepowerups.com/help-support/excel-function-reference/excel-text-analyzer/pwrsimilarity/ .

Mais cela fonctionne assez bien pour comparer le texte de la colonne A à celui de la colonne B.