Все мы знаем хорошо известную функцию VLOOKUP(), которая помогает нам совмещать данные из разных таблиц. Однако данная функция имеет один существенный недостаток – она не может совмещать подобные значения, то есть если в слове допущена ошибка – то совпадения уже не будет.
Чтобы иметь возможность совмещать приблизительные значения, мы можем создать собственную функцию. Давайте назовем ее FuzzyLookup().
Представим, что у нас есть два списка. И в том, и в другом примерно одни и те же элементы, но записаны они могут быть немного по-разному. Задача - подобрать каждому элементу в первом списке максимально схожий элемент из второго списка, т.е. реализовать поиск ближайшего максимально схожего текста.
Большой вопрос, в данном случае, что считать критерием "схожести". Просто количество совпадающих символов? Или количество совпадений, идущих подряд? Учитывать ли регистр символов или пробелы? Что делать с разным расположением слов во фразе? Вариантов много и однозначного решения нет – для каждой ситуации тот или иной будет лучше других.
В нашем случае мы реализуем самый простой вариант – поиск по максимальному количеству совпадений символов. Он не идеален, но для большинства ситуаций работает вполне надежно.
Чтобы добавить функцию FuzzyLookup , откройте меню Tools - Macros - Edit Macros... , выберите Module1 и скопируйте следующий текст в модуль:
Function FuzzyLOOKUP(LookupValue As String, SrcTable As Variant, Optional SimThreshold As Single) As String ' moonexcel.com.ua Dim Str As String Dim CellArray As Variant Dim StrArray As Variant If IsMissing(SimThreshold) Then SimThreshold = 0 Str = LCase(LookupValue) StrArray = Split(Str) StrExt = UBound(StrArray) For Each Cell In SrcTable CellArray = Split(LCase(Cell)) CellExt = UBound(CellArray) CellRate = 0 ' Проверяем каждое слово в поисковой фразе For x = 0 To StrExt StrWord = StrArray(x) If Len(StrWord) = 0 Then GoTo continue_x MaxStrWordRate = 0 ' Проверяем каждое слово в очередной ячейке из исходной таблицы значений For i = 0 To CellExt CellWord = CellArray(i) If Len(CellWord) = 0 Then GoTo continue_i FindCharNum = OccurrenceNum(StrWord, CellWord) StrWordRate = FindCharNum / Max(Len(StrWord),Len(CellWord)) If StrWordRate > MaxStrWordRate Then MaxStrWordRate = StrWordRate continue_i: Next i CellRate = CellRate + MaxStrWordRate continue_x: Next x ' Сохраняем лучшее совпадение If CellRate > MaxCellRate Then MaxCellRate = CellRate BestCell = Cell FindCharNum = OccurrenceNum(Str, Cell) SimRate = FindCharNum / Max(Len(Str),Len(Cell)) End If Next Cell IF SimRate >= SimThreshold Then IF SimThreshold = -1 Then ReturnValue = BestCell + " (" + Format(SimRate, "0.00") + ")" ElseIf SimThreshold = -2 Then ReturnValue = Format(SimRate, "0.00") Else ReturnValue = BestCell End If Else ReturnValue = "" End If FuzzyLOOKUP = ReturnValue End Function Function OccurrenceNum(ByVal SourceString As String, ByVal TargetString As String) For i = 1 To Len(SourceString) ' Ищем вхождение каждого символа Position = InStr(1, TargetString, Mid(SourceString, i, 1), 1) ' Увеличиваем счетчик совпадений If Position > 0 Then Count = Count + 1 ' Удаляем найденный символ TargetString = Left(TargetString, Position - 1) + Right(TargetString, Len(TargetString) - Position) End If Next i OccurrenceNum = Count End Function Function Max(ByVal value1 As Variant, ByVal value2 As Variant) If value1 > value2 Then Result = value1 Else Result = value2 End If Max = Result End Function
Далее, закройте Macro Editor и вернитесь на рабочий лист LibreOffice Calc - теперь вы можете воспользоваться нашей новой функцией FuzzyLookup() .
Вы также можете воспользоваться функцией FUZZYLOOKUP() установив бесплатное расширение YouLibreCalc.oxt или его полнофункциональную версию YLC_Utilities.oxt .
После этого данная функция будет доступна во всех файлах, которые будут открыты в LibreOffice Calc.