Servus zusammen,
in vielen Fällen ist es möglich, dass der Nutzer nach einem String gefragt wird und er dabei einen Tippfehler macht. Google fragt einen dann "Meinten Sie ...".
Ich habe etwas Ähnliches in VBA realisiert.
Für die Methode wird ein Array namens Dictionary angelegt in das man alle Begriffe hineinschreibt, die als Input erlaubt sind.
Wenn man die Methode DidYouMeanDictionary aufruft, vergleicht er den der Methode übergebenen String mit jedem einzelnen Eintrag im Array Dictionary und zählt die Unterschiede. Die Methode gibt dann denjenigen Eintrag aus Dictionary zurück, der dem Input am ähnlichsten ist (also am wenigsten Unterschiede aufweist).
Prinzipiell können beliebige Strings in beliebiger Anzahl mit den üblichen Methoden in das Array Dictionary geladen werden, hier ist (weil ich es in meinem Anwendungsfall so brauche) eine Methode LoadMonthsToDictionary, die die 12 Monate in das Array lädt mit dabei. Am Besten ist es jedoch, wenn der Anwendungsfall bereits auf wenige Begriffe reduziert ist, dann ist die Treffergenauigkeit auch höher.
Bekannte Issues:
-Wenn sich der Input und das Vergleichswort in der Länge unterscheiden, kann es unter Umständen zu falschen Angaben in der Statistik kommen, wenn man printStats auf true setzt.
Hier der Source-Code (Unter Excel 2013 ausführlich getestet):
Viele Grüße,
vatbub
in vielen Fällen ist es möglich, dass der Nutzer nach einem String gefragt wird und er dabei einen Tippfehler macht. Google fragt einen dann "Meinten Sie ...".
Ich habe etwas Ähnliches in VBA realisiert.
Für die Methode wird ein Array namens Dictionary angelegt in das man alle Begriffe hineinschreibt, die als Input erlaubt sind.
Wenn man die Methode DidYouMeanDictionary aufruft, vergleicht er den der Methode übergebenen String mit jedem einzelnen Eintrag im Array Dictionary und zählt die Unterschiede. Die Methode gibt dann denjenigen Eintrag aus Dictionary zurück, der dem Input am ähnlichsten ist (also am wenigsten Unterschiede aufweist).
Prinzipiell können beliebige Strings in beliebiger Anzahl mit den üblichen Methoden in das Array Dictionary geladen werden, hier ist (weil ich es in meinem Anwendungsfall so brauche) eine Methode LoadMonthsToDictionary, die die 12 Monate in das Array lädt mit dabei. Am Besten ist es jedoch, wenn der Anwendungsfall bereits auf wenige Begriffe reduziert ist, dann ist die Treffergenauigkeit auch höher.
Bekannte Issues:
-Wenn sich der Input und das Vergleichswort in der Länge unterscheiden, kann es unter Umständen zu falschen Angaben in der Statistik kommen, wenn man printStats auf true setzt.
Hier der Source-Code (Unter Excel 2013 ausführlich getestet):
Visual Basic-Quellcode
- Public Dictionary() As String
- Function countDifferences(str1 As String, str2 As String) As Long
- 'Counts the differences between str1 and str2 (different chars, removed chars, added chars)
- Dim lngC1CharLength As Long
- Dim CHARCHANGECOUNT As Long
- CHARCHANGECOUNT = 0
- For i = 1 To Application.WorksheetFunction.Max(Len(str1), Len(str2))
- If Len(str1) < Len(str2) Then
- If InStr(1, Mid(str2, i, 1 + Len(str2) - Len(str1)), Mid(str1, i, 1), vbTextCompare) = 0 Then
- CHARCHANGECOUNT = CHARCHANGECOUNT + 1
- End If
- ElseIf Len(str1) > Len(str2) Then
- If InStr(1, Mid(str2, Application.WorksheetFunction.Max(1, i - (Len(str1) - Len(str2))), 1 + Len(str1) - Len(str2)), Mid(str1, i, 1), vbTextCompare) = 0 Then
- CHARCHANGECOUNT = CHARCHANGECOUNT + 1
- End If
- Else
- If Mid(str1, i, 1) <> Mid(str2, i, 1) Then
- CHARCHANGECOUNT = CHARCHANGECOUNT + 1
- End If
- End If
- Next
- countDifferences = CHARCHANGECOUNT + Application.WorksheetFunction.Max(Len(str2) - Len(str1), 0)
- End Function
- Public Sub LoadMonthsToDictionary(Optional BeVerbose As Boolean = False)
- 'Loads a sample dictionary consisting of the german names for the months of a year.
- Dictionary = Split("Januar, Februar, März, April, Mai, Juni, Juli, August, September, Oktober, November, Dezember", ", ")
- If BeVerbose = True Then
- Debug.Print "Loaded the following words to the dictionary:"
- For Each word In Dictionary
- Debug.Print " " & word
- Next
- End If
- End Sub
- Public Function DidYouMeanDictionary(text As String, Optional printStats As Boolean = False) As String
- 'Compares text with every word in the dictionary using the countDifferences-function and returns the most similar word.
- 'This only works properly for single words.
- On Error GoTo Fehler
- Dim MinDiff, MinDiffIndex
- Dim DictString As String, DiffString As String
- MinDiff = countDifferences(text, Dictionary(0))
- MinDiffIndex = 0
- DictString = Dictionary(0) & " "
- DiffString = FormatNumber(countDifferences(text, Dictionary(i)), Len(Dictionary(i))) & " "
- For i = 1 To UBound(Dictionary)
- If MinDiff > countDifferences(text, Dictionary(i)) Then
- MinDiff = countDifferences(text, Dictionary(i))
- MinDiffIndex = i
- End If
- DictString = DictString & Dictionary(i) & " "
- DiffString = DiffString & FormatNumber(countDifferences(text, Dictionary(i)), Len(Dictionary(i))) & " "
- Next i
- DidYouMeanDictionary = Dictionary(MinDiffIndex)
- If printStats = True Then
- Debug.Print ""
- Debug.Print "Analysis stats: Differences between " & text & " and ..."
- Debug.Print DictString
- Debug.Print DiffString
- Debug.Print ""
- Debug.Print "Chars to be added to get from " & text & " to " & Dictionary(MinDiffIndex) & ": " & Application.WorksheetFunction.Max(Len(Dictionary(MinDiffIndex)) - Len(text), 0)
- Debug.Print "Chars to be removed to get from " & text & " to " & Dictionary(MinDiffIndex) & ": " & Application.WorksheetFunction.Max(Len(text) - Len(Dictionary(MinDiffIndex)), 0)
- Debug.Print "Chars to be exchanged to get from " & text & " to " & Dictionary(MinDiffIndex) & ": " & Application.WorksheetFunction.Max(MinDiff - Application.WorksheetFunction.Max(Len(text) - Len(Dictionary(MinDiffIndex)), 0) - Application.WorksheetFunction.Max(Len(Dictionary(MinDiffIndex)) - Len(text), 0), 0)
- Debug.Print ""
- End If
- Exit Function
- Fehler:
- Err.Raise 1234, "CountDifferences", "No Dictionary is specified. Please specify a dictionary by filling the global array 'Dictionary' with values." & vbCrLf & vbCrLf & "Exact error description:" & vbCrLf & Err.Description
- End Function
- Public Function FormatNumber(num As Double, length As Long) As String
- 'Adds zeros in front of the number num sothat it meets the given length.
- For i = 1 To length - Len(CStr(num))
- FormatNumber = FormatNumber & " "
- Next i
- FormatNumber = FormatNumber & CStr(num)
- End Function
Viele Grüße,
vatbub