Vba нечеткий поиск excel

Проблема нечёткого поиска

Когда мы имеем дело с текстом, вводимым человеком, то в нём неизбежны ненамеренные ошибки. Вместо «пер. Гоголя» человек может набрать «пер. Ноголя» просто потому, что промахнётся по нужной клавише и нажмёт соседнюю. В виду этого, возникает задача поставить в соответствие введеному слову слово словарное, которое в наибольшей степени похоже на то, что ввёл пользователь. Классическая задача — верификация названий улиц, населенных пунктов и т.п. Обычный поиск тут бессилен, так как введенное слово в словаре отсутствует. Обычный поиск в состоянии только установить этот факт, но не в состоянии предложить пользователю на выбор наиболее близкие варианты. Нужна реализация нечёткого поиска.

Что я предлагаю

Для тех, кто спешит, сразу сообщаю, что, если тема актуальна, то я предлагаю вам воспользоваться своей пользовательской функцией рабочего листа, которая называется FS_GetClosestWord и имеет 2 обязательных параметра и 4 необязательных.

Формат вызова: =FS_GetClosestWord( What ; Where ; [NumItem] ; [MinLen] ; [Compare] ; [Dbg] ) , где:

  • What — ссылка на ячейку, которая содержит искомую строку. Обратите внимание, что текстовая константа в формуле не будет воспринята, только ссылка на ячейку;

  • Where — ссылка на диапазон, содержащий словарь, в котором необходимо подобрать наиболее близкое к What слово. Словарь может быть в виде столбца, строки или состоять из произвольного размера диапазона. Имейте только в виду, что, задав словарь из большого количества слов (скажем больше 10000), или, если словарь содержит много очень длинных слов, то вы рискуете надолго подвесить систему;

  • [NumItem] — в процессе поиска строится коллекция наиболее подходящих слов, которые ранжируются по определенному алгоритму. NumItem определяет
    номер возвращаемого слова из этой коллеции. NumItem=1 возвращает наиболее близкое по мнению используемого алгоритма слово. Если указанный номер слишком велик и результирующая коллекция не содержит такого числа элементов, то возвращается ошибка #Н/Д;

  • [MinLen] — минимальная длинна буквенных комбинаций, на которые разбиваются слова из словаря и, которые потом ищутся в слове из What. Не может быть меньше 3. Если укажете меньше 3 или не укажете вовсе, то будет использовано значение 3;

  • [Compare] — тип сравнения строк: с учётом регистра или без учёта. 0 — с учётом регистра, 1 — без учёта регистра;

  • [Dbg] — если указать тут число большее 1, то включится режим отладки и в зависимости от того, что вы тут укажаете, сможете получить:

    • 1 — стандартное поведение, возвращающее близкое слово из Where;

    • 2 — найденная подстрока;

    • 3 — слепок найденного словарного слова;

    • 4 — разница по модулю между слепком найденного и искомого слова, которая используется для ранжирования найденных слов по уровню схожести с оригинальным словом (чем меньше разница, тем считаются более похожими слова).

Большинство пользователей обойдутся первыми двумя параметрами.

Скачать файл с функцией

Скачать

Если будете переносить руками в свой Excel VBA проект, то не забудьте помимо модуля Fuzzy, также перенести класс Search.

Теория нечёткого поиска

Изучая вопрос, в начале заглянул к Николаю Павлову в этот его рецепт. Даже нашёл у него ошибки. Однако с самого начало было понятно, что предложенный алгоритм для общего случая будет неприемлем из-за медленной скорости, поэтому изыскания были продолжены. Отличный обзор алгоритмов нечёткого поиска дан в этой статье. Для своей реализации я выбрал метод N-грамм с привлечением хэширования по сигнатуре для оценки найденных вариантов.

Предположим, что у нас в словаре есть слово ПОМИДОР. Мой алгоритм разбивает это слово на подстроки длиной от 7 до 3 символов. 7 — длина слова в данном случае, а комбинации символов короче трёх символов использовать особого смысла нет.

  • 7 символов — 1 вариант (ПОМИДОР)

  • 6 символов — 2 варианта (ПОМИДО, ОМИДОР)

  • 5 символов — 3 варианта (ПОМИД, ОМИДО, МИДОР)

  • 4 символа — 4 варианта (ПОМИ, ОМИД, МИДО, ИДОР)

  • 3 символа — 5 вариантов (ПОМ, ОМИ, МИД, ИДО, ДОР)

  • Итого мы получили из слова ПОМИДОР 15 разных буквенных комбинаций.

Все эти 15 комбинаций я помещаю в словарь. В этот же словарь заносятся все новые комбинации, образующиеся от остальных словарных слов. Далее берётся искомое слово и точно также разбивается на подстроки и прогоняется на совпадение с созданным словарём буквенных комбинаций. Все срабатывания заносятся в коллекцию и ранжируются по уровню похожести.

Проблемы реализации нечёткого поиска

На мой взгляд основная проблема тут — скорость поиска. Надо заметить, что прежде, чем я получил тот код, который вам предлагаю, я написал промежуточную статью про эффективность структур данных и перепробовал массу промежуточных вариантов структур и алгоритмов.

Поскольку всё реализовано в виде формулы рабочего листа, то основной способ улучшить производительность — это, чтобы каждая формула не расчитывала свою коллекцию буквенных комбинаций словаря, а использовала результаты однажды проделанной работы. Это было сделано через глобальные структуры. Однако это всё означает, что формула не отслеживает изменения в массиве Where. То есть считается, что диапазон Where статический и меняется редко.

Надеюсь вы найдёте этот функционал полезным. Если вам данное решение по какой-то причине не подошло или нуждается в серьёзной модификации, то дайте знать, возможно, я его доработаю, так как тема довольно интересная.

Читайте также:

  • Извлекаем список уникальных значений из необработанных данных

  • Формирование случайных списков на основе справочника

  • Расширенное сравнение двух колонок (списков)

Fuzzy text matching is very useful when you want to compare a text string against other strings that don’t have to be identical. You still, however, want to find the one that is closest in terms of words. Fuzzy matching is very useful when e.g. you want to compare a user question against a database of solutions/answers. That is basically what Google does everyday. Rarely will your question ideally match the title of a blog or news article so Google tries to rank pages using fuzzy matching to find ones that are closest to your query.

Microsoft Fuzzy Lookup AddIn

As Fuzzy matching / lookup is a frequent feature Excel users required Microsoft decide to create their own Fuzzy Lookup AddIn. The AddIn basically allows you to lookup columns from another table using Fuzzy Matching and copy them to your source table.

Go here to find Microsoft Official Fuzzy Lookup AddIn for Excel

When playing with the Fuzzy Lookup AddIn I wasn’t happy with it. I had an enormous database of user Questions and Answers and I wanted to have a choice of which items it will match for each of my records basis the user query. Often the fuzzy match algorithm would suggest a match that wasn’t perfect given context. Hence I decide to create my own Fuzzy Match VBA UserForm….

Custom Fuzzy Match using VBA UserForm

What I wanted was an easy way to lookup my query against a Knowledge Base of questions that are ranked in terms of their match against the query. The closer the query is to the question the higher the match. That way I can decide whether indeed I want to take the answer from the question with the highest match rate or maybe one of the below. The additional requirement was to ignore so called “stop words” in my query (the, a, it etc.) as these could generate a lot of false matches, while I wanted fuzzy matching only focus on the keywords.
Example Fuzzy Match
To show you how the Fuzzy Match VBA UserForm works I created a simple Knowledge Base of Excel/VBA related questions. The KB consists of 3 basis columns: Questions, Answer and Category. The Category column is especially useful as looking at the query you might want to limit the Fuzzy algorithm to run on only a subset of items in your database.

Example Knowledge Base of Questions and Answers

An example Knowledge Base

Designing the Fuzzy Match UserForm

Below a quick overview of the Fuzzy Match VBA UserForm if you want to see it in action:

Below you can find the design of the VBA Fuzzy Match UserForm.

Fuzzy Match UserForm

The design of the VBA Fuzzy Match UserForm

Each field is explained below:

  • Text Selected – text from the Excel cell you selected in your workbook before running the VBA macro
  • Search Question – if you want to override the “Text Selected” field simply type your query here and hit the Search button again. A typical scenario for this field is when you see that the result for your “Text Selected” don’t return satisfactory results and you would like to adjust the query
  • Category(s) – if you want to improve the algorithm performance or simply reduce the categories to be searched then select the ones you are interested in
  • Search – the Search button will run the algorithm and return results to the “Results” table
  • Selected Question / Selected Answer – when you click on one of the results these fields will show the full text of the Question and Answer column. This makes it easier to copy the results where needed

The VBA Code

Initializing the UserForm

Firstly we will initialize our UserForm and assure it is showing us the current list of categories in our “KnowledgeBase” worksheet:

Private Sub UserForm_Initialize()
    Set catDict = GetListofCategories()
    For Each it In catDict.keys
        lbCategory.AddItem it
    Next it
    lbCategory.AddItem "Any"
    For i = 0 To lbCategory.ListCount - 1
        lbCategory.Selected(i) = True
    Next i
    tbSelectedQuestion.Text = Selection.Value
End Sub

Function GetListofCategories()
    Dim question As Range
    Set dict = CreateObject("Scripting.Dictionary")
    Set wsQnA = GetQnAWorksheet
    For Each question In wsQnA.Range("C:C").SpecialCells(xlCellTypeConstants)
        If question.Row > 1 Then
            If Not dict.Exists(question.Value) Then
                dict.Add question.Value, 1
            End If
        End If
    Next question
    Set GetListofCategories = dict
End Function

Function GetQnAWorksheet() As Worksheet
    Dim ws As Worksheet
    For Each ws In ActiveWorkbook.Sheets
        If ws.Name Like "KnowledgeBase*" And ws.Visible Then
            Set GetQnAWorksheet = ws
            Exit Function
        End If
    Next ws
    MsgBox "KnowledgeBase worksheet not found!~", vbCritical + vbOKOnly, "Error"
    Set GetQnAWorksheet = Nothing
End Function

Function for removing Stop Words

Before we focus on generating matches let us focus for a sec on creating a function that will remove stop words from a given sentence. This will help us get rid of all those unnecessary words like “the, it, this” etc. that will dilute the fuzzy algorithm.

Function RemoveStopWords(sentence As String) As Collection
    If IsEmpty(stopWords) Then stopWords = Split("a;about;above;after;again;against;all;am;an;and;any;are;aren't;as;at;be;because;been;before;being;below;between;both;but;by;can't;cannot;chat;could;couldn't;did;didn't;do;does;doesn't;doing;don't;down;during;each;few;for;from;further;had;hadn't;has;hasn't;have;haven't;having;he;he'd;he'll;he's;her;here;here's;hers;herself;hi;him;himself;his;how;how's;i;i'd;i'll;i'm;i've;if;in;into;is;isn't;it;it's;its;itself;let's;me;more;most;mustn't;my;myself;need;needs;no;nor;not;of;off;on;once;only;or;other;ought;our;ours;out;over;own;same;shan't;she;she'd;she'll;she's;should;shouldn't;so;some;such;than;that;that's;the;their;theirs;them;themselves;then;there;there's;these;they;they'd;they'll;they're;they've;this;those;through;to;too;under;until;up;very;was;wasn't;we;we'd;we'll;we're;we've;were;weren't;what;what's;when;when's;where;where's;which;while;who;who's;whom;why;why's;with;won't;would;wouldn't;you;you'd;you'll;you're;you've;your;yours;yourself;yourselves;?;!;" & _
             "-;,;", ";")
    Dim stopR As Range, r As Variant, col As Collection
    Set col = New Collection
    For Each w In Split(sentence, " ")
        If Not (IsNumeric(Trim(w))) Then
            w = Trim(w)
            If Len(w) > 0 Then col.Add w
        End If
    Next w
    For Each r In stopWords
        For i = col.Count To 1 Step -1
            If UCase(col(i)) = UCase(r) Then
                col.Remove i
            End If
        Next i
    Next r
    Set RemoveStopWords = col
End Function

You probably noticed I embedded a lot of words directly in the function. This makes it easy to add or remove stop words quickly.

Fuzzy Matching algorithm

Now for the meaty part :). Below the key logic for generating the results:

Public stopWords As Variant
Dim selectedChat As Range
Private Sub cbSearch_Click()
    'Clear Search worksheet
    Set selectedChat = Selection
    Dim wsRes As Worksheet: Set wsRes = GetSearchWorksheet
    selectedChat.Worksheet.Activate
    'Remove stop words from question
    Dim qCol As Collection
    Set qCol = RemoveStopWords(Selection.Value)
    'Search
    Dim wsQnA As Worksheet, r As Range, saCol As Collection, sa() As String, saIndex As Long
    Dim dict As Object, dstR As Range, startCount As Long, pMax As Long, currProgress As Long
    Set dict = CreateObject("Scripting.Dictionary")
    For i = 0 To lbCategory.ListCount - 1
        If lbCategory.Selected(i) Then
            dict.Add lbCategory.List(i), lbCategory.List(i)
        End If
    Next i
    'Search question matching Service Area, search query and calculate match
    Set wsQnA = GetQnAWorksheet
    If wsQnA Is Nothing Then Exit Sub
    startCount = wsRes.Range("A:A").SpecialCells(xlCellTypeConstants).Count
    pMax = wsQnA.Range("A:A").SpecialCells(xlCellTypeConstants).Count
    For Each r In wsQnA.Range("A:A").SpecialCells(xlCellTypeConstants)
        If dict.Exists(r.Offset(0, 4).Value) Or IsEmpty(r.Offset(0, 4).Value) And r.Row > 1 Then
            If tbSearch.Value = vbNullString Or InStr(1, r.Value, tbSearch.Value, vbTextCompare) > 0 Then
                Set dstR = wsRes.Range("A1").Offset(startCount):  startCount = startCount + 1
                dstR.Value = r.Value
                dstR.Offset(0, 1).Value = r.Offset(0, 1).Value
                dstR.Offset(0, 2).Value = r.Offset(0, 2).Value
                dstR.Offset(0, 3).Value = CalculateMatch(qCol, r.Value)
                dstR.Offset(0, 3).NumberFormat = "0%"
            End If
        End If
        currProgress = currProgress + 1
        If currProgress Mod 100 = 0 Then
            lStatus.Caption = "Searching " & Format(CDbl(currProgress) / pMax, "0%")
            DoEvents
        End If
    Next r
    'Display Search sorted by Match
    If wsRes.UsedRange.Rows.Count > 0 Then
        With wsRes.Sort
            .SortFields.Clear
            .SortFields.Add2 Key:=GetSearchLastColumn(wsRes), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
            .SetRange wsRes.UsedRange
            .Header = xlYes
            .MatchCase = False
            .Orientation = xlTopToBottom
            .SortMethod = xlPinYin
            .Apply
        End With
    End If
    
    lbResult.RowSource = GetSearchRangeAddress(wsRes)
    lStatus.Caption = "" & lbResult.ListCount & " Questions found"
End Sub
Function GetSearchRangeAddress(ws As Worksheet)
    GetSearchRangeAddress = "'" & ws.Name & "'!" & Range(ws.Range("A2"), ws.Cells(ws.UsedRange.Rows.Count, ws.UsedRange.Columns.Count)).AddressLocal
End Function
Function GetSearchLastColumn(ws As Worksheet) As Range
    Set GetSearchLastColumn = Range(ws.Range("D2"), ws.Cells(ws.UsedRange.Rows.Count, ws.UsedRange.Columns.Count))
End Function

Function CalculateMatch(sentCol As Collection, sentence As String) As Double
    Dim m As Long, s() As String
    s = Split(sentence, " ")
    For Each w In sentCol
        For Each ws In s
            If UCase(ws) = UCase(w) Then
                m = m + 1
                Exit For
            End If
        Next ws
    Next w
    CalculateMatch = m / sentCol.Count
End Function
Sub CreateSearchResultsHeader(ws As Worksheet)
    ws.Range("A1").Value = "Questions"
    ws.Range("B1").Value = "Answer"
    ws.Range("C1").Value = "Category"
    ws.Range("D1").Value = "Match"
End Sub
Sub AddSearchResultsRow(ws As Worksheet, rowNum As Long, question As String, answer As String, sa As String, match As String)
    ws.Range("A" & rowNum).Value = question
    ws.Range("B" & rowNum).Value = answer
    ws.Range("C" & rowNum).Value = sa
    ws.Range("D" & rowNum).Value = match
End Sub
Function GetSearchWorksheet()
    Dim ws As Worksheet
    For Each ws In ActiveWorkbook.Sheets
        If ws.Name = "SearchResults" Then
            ws.UsedRange.Clear
            CreateSearchResultsHeader ws
            Set GetSearchWorksheet = ws
            Exit Function
        End If
    Next ws
    Set ws = ActiveWorkbook.Sheets.Add
    ws.Name = "SearchResults"
    CreateSearchResultsHeader ws
    Set GetSearchWorksheet = ws
End Function

The above code will do the following – compare the query to each question from the selected categories, calculate the match and add it to a temporary worksheet. Once done the table in the form will be connected to the range in the temporary worksheet and displayed.

Below a few other pieces of code that help display the Q/A in the text boxes and help us clean-up:

Private Sub lbResult_Click()
    'Display question and answer in textbox below
    For i = 0 To lbResult.ListCount - 1
        If lbResult.Selected(i) Then
            tbQ.Value = lbResult.List(i, 0)
            tbA.Value = lbResult.List(i, 1)
        End If
    Next i
End Sub

Private Sub UserForm_Terminate()
    On Error Resume Next
    Application.DisplayAlerts = False
    ActiveWorkbook.Sheets("SearchResults").Delete
    Application.DisplayAlerts = True
End Sub

Download the entire VBA Code Module

If you want to download the entire VBA Code Module for the Excel VBA Fuzzy Match UserForm click the download button below:
Download

 

Jack Famous

Пользователь

Сообщений: 10848
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#1

17.12.2019 17:27:56

Доброго времени суток, Планетяне!

Знаю несколько вариантов (ссылки внизу), но всё не то — лучше надстройки варианта не нашёл, отсюда вопрос, можно ли ей управлять через VBA и как?
Вопрос переноса кода из надстройки не задаю, т.к. там, как я понял, вообще не VBA…
Ну и есть ещё вариант использовать нечто похожее — делитесь, кто знает  :idea:

Ссылки

Изменено: Jack Famous31.08.2021 12:03:53

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

 

Prosvetov

Пользователь

Сообщений: 52
Регистрация: 29.04.2019

Вариант с PQ, как понимаю, тоже не подходит?

 

bedvit

Пользователь

Сообщений: 2477
Регистрация: 02.04.2015

Виталий

#3

17.12.2019 18:18:53

Цитата
Jack Famous написал:
лучше надстройки варианта не нашёл, отсюда вопрос, можно ли ей управлять через VBA

Где эта надстройка?

«Бритва Оккама» или «Принцип Калашникова»?

 

БМВ

Модератор

Сообщений: 21378
Регистрация: 28.12.2016

Excel 2013, 2016

bedvit, Виталий, пока еще все

тут

По вопросам из тем форума, личку не читаю.

 

bedvit

Пользователь

Сообщений: 2477
Регистрация: 02.04.2015

Виталий

#5

18.12.2019 01:48:20

Посмотрел.
Написано:
The following libraries are required and will be installed if necessary:
.NET 4.5
VSTO 4.0

Но, при беглом осмотре, написана она не на .NET (по крайней мере установщик)

Посмотрел внимательнее, setup.exe — это бинарник.
FuzzyLookupAddInForExcel.dll — .NET

Сборка

Скрытый текст

ConfigurationForm

Скрытый текст

т.к. насколько я понимаю код закрыт, поэтому завтра я удалю сей «подсмотренный» код.

Резюме, надстройка написана на .NET, при желании можно добавив функционала и API (для VBA), собрать свою, при определенных знаниях.
Это называется хакинг. Мне это не интересно.

Изменено: bedvit18.12.2019 16:33:01
(Удалил исходники, в соответствии с лицензией от правообладателя (bedvit))

«Бритва Оккама» или «Принцип Калашникова»?

 

Jack Famous

Пользователь

Сообщений: 10848
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#6

18.12.2019 09:24:00

Цитата
Prosvetov: Вариант с PQ

подходит всё — вопрос, как это будет работать. Покажете?  :)

Цитата
bedvit: Это называется хакинг

то есть использовать функционал надстройки кроме как ручками легально не получается — правильно?

Изменено: Jack Famous18.12.2019 09:26:14

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

 

БМВ

Модератор

Сообщений: 21378
Регистрация: 28.12.2016

Excel 2013, 2016

#7

18.12.2019 09:39:11

Цитата
Jack Famous написал:
Покажете?

и Prosvetление наступит   :D

По вопросам из тем форума, личку не читаю.

 

PooHkrd

Пользователь

Сообщений: 6602
Регистрация: 22.02.2017

Excel x64 О365 / 2016 / Online / Power BI

#8

18.12.2019 09:52:21

Цитата
Jack Famous написал:
подходит всё — вопрос, как это будет работать. Покажете?

В О365 с обновления от июня 2019 года появилась функция

Table.FuzzyJoin

. Как применять описано

здесь

В VBA можно затаскивать данные в таблицу потом сфомировать макросом текст запроса, результат выгрузить на лист в таблицу и далее работать с ним средствами VBA. Не знаю на сколько быстро это будет работать, но не уверен даже в наличии у вас О365 с нужными обновлениями.

Вот горшок пустой, он предмет простой…

 

egonomist

Пользователь

Сообщений: 409
Регистрация: 21.12.2012

День добрый.

Всегда пользуюсь fuzzyvlookup функцией от Уважаемого

Pharmaprofi

.
В надстройке все модули открыты. Просто переношу модуль в свою книгу и использую как udf или в vba.

Еще раз огромное спасибо

Pharmaprofi

за труд.

 

ZVI

Пользователь

Сообщений: 4328
Регистрация: 23.12.2012

Интересно, что по

ссылке

для скачивания Fuzzy Lookup Add-In for Excel в разделе Install Instructions написано об условиях лицензии в документе ‘LicenseTerms.rtf’: «Read the license terms in the ‘LicenseTerms.rtf‘ document.»

А в п.2 документа LicenseTerms.rtf был указан срок действия лицензии до 30 июля 2019г.
«2. TERM. The term of this agreement is until 30/07/2019 (day/month/year), or commercial release of the software, whichever is first.»

Получается, что юридически срок использования надстройки закончился, несмотря на то, что технически она работоспособна.

Изменено: ZVI18.12.2019 10:21:20

 

Nordheim

Пользователь

Сообщений: 3154
Регистрация: 18.04.2017

bedvit, для саморазвития, надстройка написана на C#?

«Все гениальное просто, а все простое гениально!!!»

 

ZVI

Пользователь

Сообщений: 4328
Регистрация: 23.12.2012

Кому интересно —

здесь

есть много разных вариантов кода Fuzzy Matching. Но там нет кода с алгоритмом, использованным в Fuzzy Lookup Add-In for Excel.

 

bedvit

Пользователь

Сообщений: 2477
Регистрация: 02.04.2015

Виталий

#13

18.12.2019 12:52:43

Nordheim, да.

Цитата
Jack Famous написал:
использовать функционал надстройки кроме как ручками легально не получается

почему же, используйте в том виде, в котором она распространяется. Владимир выше пишет, что технически она работоспособна (я не тестировал).
ZVI, Владимир правильно ли я понял, что с 30/07/19 мой пост 5 не является взломом лицензионного софта?

«Бритва Оккама» или «Принцип Калашникова»?

 

ZVI

Пользователь

Сообщений: 4328
Регистрация: 23.12.2012

#14

18.12.2019 13:39:35

Цитата
bedvit написал: правильно ли я понял, что с 30/07/19

Виталий, добрый день.
Независимо от даты, запрещено:
5. SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not
reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation;

По поводу #5 — не знаю, не юрист ))

 

bedvit

Пользователь

Сообщений: 2477
Регистрация: 02.04.2015

Виталий

Владимир, спасибо. Удалил исходники в п.5, оставил только данные по сборке.

«Бритва Оккама» или «Принцип Калашникова»?

 

Jack Famous

Пользователь

Сообщений: 10848
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#16

18.12.2019 17:27:54

Прошу прощения, что не отвечал, хотя видел — очень много работы. Итак…

Цитата
PooHkrd: В О365 с обновления от июня 2019 года появилась функция  Table.FuzzyJoin

да — пока это, пожалуй, только для справки, хотя бы из-за подписки. Для справки, чтобы иметь ввиду — безусловно полезно, я не знал. Спасибо

Цитата
egonomist: Всегда пользуюсь fuzzyvlookup функцией от Уважаемого  Pharmaprofi

при беглом взгляде на код есть серьёзные подозрения, что это не его код. Вопрос также в том, что именно этот код делает, т.к. нечёткий поиск может быть сильно разным. За ссылку спасибо

ZVI, огромное спасибо за примеры кодов (кроме них мне пока зацепиться не за что), разбор надстройки и прочее!
bedvit, спасибо за погружение в вопрос

Изменено: Jack Famous18.12.2019 17:28:41

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

Like — оператор VBA для сравнения строки с шаблоном. Нечеткий поиск

Подробности

Категория: Основы VBA

Опубликовано: 17 января 2013

Кроме сравнения строк с использованием операторов «равно», «больше» и «меньше», в языке Visual Basic for Applications (VBA) доступен оператор Like, который можно использовать только для сравнения строк.  

Как программно найти и удалить определенные строки в Excel, используя VBA-оператор Like

http://macros-vba.ru/makrosy/excel/132-kak-najti-stroki-v-excel-poisk-strok-slov-i-simvolov-v-excel

Sub Udalenie_Strok_Po_Shablonu()

    Dim r As Long, FirstRow As Long, LastRow As Long
    Dim Region As Range, iRow As Range, Cell As Range
    Dim Shablon As String
 
    Shablon = "здесь вводится искомый текст"
 
    Set Region = ActiveSheet.UsedRange
    FirstRow = Region.Row
    LastRow = Region.Row - 1 + Region.Rows.Count 
        For r = LastRow To FirstRow Step -1
        Set iRow = Region.Rows(r - FirstRow + 1)
            For Each Cell In iRow.Cells
                If Cell Like Shablon Then
                    Rows(r).Delete
                End If
            Next Cell
        Next r
End Sub

Сравнение строки с шаблоном

Оператор Like выполняет особый тип операции сравнения строк, определяя совпадает ли строка с заданным образцом (шаблоном). Этот оператор используется также для поиска в текстовой информации слов, фраз и определенных символов, совпадающих с заданным шаблоном. Такой тип поиска часто называют нечетким поиском.

Специальные символы совпадения с образцом для оператора Like

Образец, с которым должна сравниваться строка, задается при помощи различных специальных символов, представленных в таблице ниже.

Использование символов совпадения рассмотрим на примере процедуры, удаляющей всю строку активного рабочего листа, при нахождении в этой строке ячейки с искомым текстом (шаблоном).

Если Shablon=»*Круг 2#*», то на листе будут удалены все строки, в которых найдутся слова «Круг 20», «Круг 25» и так далее.

Если Shablon=»S*e», то на листе будут удалены все строки, в ячейках которых будут найдены слова «Sadie», «Salone», «Sophie», «Steve» и так далее.

Если Shablon=»P???y», то удалены будут строки со словами «Penny», «Persy», «Patty» и так далее.

Две последние спецификации символов совпадения из вышеприведенной таблицы используются для указания отдельных символов, совпадение или несовпадение с которыми нужно при поиске. Ниже приведены выражения, использующие квадратные скобки с символьным списком.

Если Shablon=»bi[dg]», то строки со словами в ячейках «bid» и «big» будут удалены, а со словами «bit» и «bin» останутся нетронутыми.

Если же Shablon=»bi[!dg]», то результат будет обратным.

Квадратные скобки можно также использовать для указания диапазона символов, совпадение или несовпадение с которыми необходимо, например Shablon=»ci[a-f]» или Shablon=»ci[!a-f]». В таких случаях диапазоны необходимо указывать от наименьшего до наибольшего символа. Квадратные скобки, в которых ничего не заключено — VBA игнорирует.

Квадратные скобки используются и в тех случаях, когда необходимо сами специальные символы сделать частью шаблона. Например, для того чтобы найти все строки, заканчивающиеся вопросительным знаком, необходимо задать шаблон следующим образом: Shablon=»*[?]».

Для совпадения со знаком дефиса в строке шаблона, дефис помещается в начало или в конец списка символов внутри квадратных скобок. Дефис, помещенный в любое другое место, задает диапазон символов.

Если Shablon=»*g[-]*», то совпадениями будут считаться выражения «big-headed», «plug-ugly», «tag-along» и так далее.

Результат сравнения строк VBA-оператором Like зависит от инструкции Option Compare. При двоичном сравнении оператор различает буквы верхнего и нижнего регистра, а при текстовом — нет.

Другие материалы по теме:

  • MsgBox — оператор VBA для вывода сообщений пользователю процедуры
  • Как удалить скрытые строки? Программное удаление скрытых строк макросом VBA.
  • Как удалить пустые строки? Программное удаление пустых строк макросом VBA
  • Как вставить/добавить новые/пустые строки в Excel?
  • Как удалить строки в Excel по условию? Удаление и скрытие пустых строк и строк, содержащих заданное значение

Кроме сравнения строк с использованием операторов «равно», «больше» и «меньше», в языке Visual Basic for Applications (VBA) доступен оператор Like, который можно использовать только для сравнения строк.  

Сравнение строки с шаблоном

Оператор Like выполняет особый тип операции сравнения строк, определяя совпадает ли строка с заданным образцом (шаблоном). Этот оператор используется также для поиска в текстовой информации слов, фраз и определенных символов, совпадающих с заданным шаблоном. Такой тип поиска часто называют нечетким поиском.

Специальные символы совпадения с образцом для оператора Like

Образец, с которым должна сравниваться строка, задается при помощи различных специальных символов, представленных в таблице ниже.

Специальные символы совпадения с образцом для оператора Like

Использование символов совпадения рассмотрим на примере процедуры, удаляющей всю строку активного рабочего листа, при нахождении в этой строке ячейки с искомым текстом (шаблоном).

Если Shablon=»*Круг 2#*», то на листе будут удалены все строки, в которых найдутся слова «Круг 20», «Круг 25» и так далее.

Если Shablon=»S*e», то на листе будут удалены все строки, в ячейках которых будут найдены слова «Sadie», «Salone», «Sophie», «Steve» и так далее.

Если Shablon=»P???y», то удалены будут строки со словами «Penny», «Persy», «Patty» и так далее.

Две последние спецификации символов совпадения из вышеприведенной таблицы используются для указания отдельных символов, совпадение или несовпадение с которыми нужно при поиске. Ниже приведены выражения, использующие квадратные скобки с символьным списком.

Если Shablon=»bi[dg]», то строки со словами в ячейках «bid» и «big» будут удалены, а со словами «bit» и «bin» останутся нетронутыми.

Если же Shablon=»bi[!dg]», то результат будет обратным.

Квадратные скобки можно также использовать для указания диапазона символов, совпадение или несовпадение с которыми необходимо, например Shablon=»ci[a-f]» или Shablon=»ci[!a-f]». В таких случаях диапазоны необходимо указывать от наименьшего до наибольшего символа. Квадратные скобки, в которых ничего не заключено — VBA игнорирует.

Квадратные скобки используются и в тех случаях, когда необходимо сами специальные символы сделать частью шаблона. Например, для того чтобы найти все строки, заканчивающиеся вопросительным знаком, необходимо задать шаблон следующим образом: Shablon=»*[?]».

Для совпадения со знаком дефиса в строке шаблона, дефис помещается в начало или в конец списка символов внутри квадратных скобок. Дефис, помещенный в любое другое место, задает диапазон символов.

Если Shablon=»*g[-]*», то совпадениями будут считаться выражения «big-headed», «plug-ugly», «tag-along» и так далее.

Результат сравнения строк VBA-оператором Like зависит от инструкции Option Compare. При двоичном сравнении оператор различает буквы верхнего и нижнего регистра, а при текстовом — нет.

Другие материалы по теме:

Here is a VBA solution which implements a rather weak fuzzy lookup. Maybe it will work on a Mac, maybe not (I’ve had mixed experiences when a colleague who has a Mac has tried to run some of my programs):

Function FLOOKUP(pat As String, arr As Variant, ColNum As Long, Optional CaseSensitive = True) As Variant
    'does a linear search of first column of array or range arr until it finds a
    'string which is a fuzzy match for pat, returning the corresponding
    'entry in column ColNum of arr. If no match is found NA is returned

    Dim A As Variant, i As Long, s As String, p As String, pStar As String

    p = IIf(CaseSensitive, pat, UCase(pat))
    pStar = "*" & p & "*"

    If TypeName(arr) = "Range" Then
        A = arr.Value
    Else
        A = arr
    End If

    For i = LBound(A) To UBound(A)
        s = A(i, 1)
        If Not CaseSensitive Then s = UCase(s)
        If p Like "*" & s & "*" Or s Like pStar Then
            FLOOKUP = A(i, ColNum)
            Exit Function
        End If
    Next i

    FLOOKUP = CVErr(xlErrNA)
End Function

In this code s is considered to be a fuzzy match of t if and only if either s Like "*" & t & "*" or t Like "*" & s & "*". In other words, if either s is a substring of t or vice-versa.

If Excel VBA for the Mac doesn’t know about xlErrNA, experimentation suggests that this is just 2042. You could always return e.g. False rather than an error code if no match is found.

The linear nature of the search implies that it probably won’t scale very well, but perhaps it will work for your application.

Индексирование списка на базе нечёткого поиска

Формуляр

Дата: Воскресенье, 18.05.2014, 21:39 |
Сообщение № 1

Группа: Друзья

Ранг: Ветеран

Сообщений: 832


Репутация:

255

±

Замечаний:
0% ±


Excel 2003, 2013

Данная тема возникла как результат эволюции Простой метрики сходства текстовых строк.
В процессе развития задача изменилась, область примененя сместилась, а сама процедура уже никак не вписывается в категорию «простой».
Итак, на данный момент мы имеем UDF TxtSimIndex_Nx2(), которая находит в указанном списке (списке поиска) наиболее подходящие ключевые словосочетания из другого списка (справочника). В качестве результата выдаёт таблицу с номером самого подходящего ключа и степень его сходства для каждой строки списка поиска.

В файле SimTextIdx_Vlad — решение под конкретную задачу от Vlad_i_mir, где индексирование запускается кнопкой.
В файле SimTextIdx — другие вариации на ту же тему: реализация как макросом, таки непосредственным вводом UDF в ячейку. На последнем листе проверочный расчёт метрики сходства для отдельно взятой пары строк. При желании можно поэкспериментировать с настройками.

Принцип работы и настроечные параметры описываются в старой теме, а также в обрывочных коммениариях в файле.
Прописывал всё, честно признаться, очень сумбурно. Сомневаюсь, что найдётся много желающих углубляться внутрь. Ну а на пользовательском уровне, разобраться, думаю, можно.
Спрашивайте, если где чего непонятно.


Excel 2003 EN, 2013 EN

 

Ответить

Vlad_i_mir

Дата: Вторник, 20.05.2014, 11:00 |
Сообщение № 2

Группа: Пользователи

Ранг: Прохожий

Сообщений: 6


Репутация:

0

±

Замечаний:
0% ±


Excel 2007

Саня, спасибо!
Такой вопрос: если увеличить константы «FRAG_REPT_LIM_1» и «WORD_NUM_LIM_1» это приведёт только к увеличению времени расчёта и потребляемых ресурсов или это отразиться ещё на чём-то?

 

Ответить

Формуляр

Дата: Вторник, 20.05.2014, 11:48 |
Сообщение № 3

Группа: Друзья

Ранг: Ветеран

Сообщений: 832


Репутация:

255

±

Замечаний:
0% ±


Excel 2003, 2013

Сами константы влияют только на ресурсы.
Но в реальности я пока ни разу в их ограничение не упирался.
Думаю, справочник на несколько тыс. записейможет потянуть. Если нет, нужно будет, видимо, группировать по городам.
Время увеличится, когда увеличится объём самой информации в справочнике. Пустые записи просто игнорируются.


Excel 2003 EN, 2013 EN

 

Ответить

Zorro063

Дата: Среда, 13.08.2014, 21:20 |
Сообщение № 4

Группа: Пользователи

Ранг: Прохожий

Сообщений: 1


Репутация:

0

±

Замечаний:
0% ±


Excel 2010

Доброго времени суток, перешел с ветки про нечеткий поиск за помощью:

В приложенном файле нужно на первый лист подтянуть значения аналитики (вторая колонка) со второго листа. Попробовал разобраться с помощью =fuzzylookup, но, ввиду очень большого справочника (больше, чем массив поиска), обработка файла оказалась ооочень долгой и результаты оказались совсем неоднозначные.

С функцией TxtSimIndex_Nx2 не пойму как работать. Получится ли использовать эту функцию в данном случае?

Очень рассчитываю на вашу помощь

К сообщению приложен файл:

6710370.xlsx
(97.9 Kb)

Сообщение отредактировал Zorro063Четверг, 14.08.2014, 08:45

 

Ответить

Формуляр

Дата: Вторник, 26.08.2014, 16:45 |
Сообщение № 5

Группа: Друзья

Ранг: Ветеран

Сообщений: 832


Репутация:

255

±

Замечаний:
0% ±


Excel 2003, 2013

Использовать можно.
Только сперва нужно справочник в порядок привести: выкинуть всякий мусор и оставить реально ключевые слова (ну или номера), по которым происходит сравнение.
Справочник в нынешнем виде со страшной силой жрёт память (поэтому в прилагаемом файле ограничен первыми 333 строками) и снижает качество сравнения за счёт огромного числа случайных несущественных совпадений.

PS: прошу извинить за замедленную реакцию, как-то пропустил ваш пост, а потом наткнулся случайно.


Excel 2003 EN, 2013 EN

Сообщение отредактировал ФормулярВторник, 26.08.2014, 16:48

 

Ответить

biokir

Дата: Среда, 01.10.2014, 14:45 |
Сообщение № 6

Группа: Пользователи

Ранг: Новичок

Сообщений: 10


Репутация:

0

±

Замечаний:
0% ±


Excel 2010

Формуляр,
Александр, прошу помочь в разрешении следующей задачки.
Во вложенном файле пример базы с которой работаю при помощи FindBestMatchTxt.
Наша база увеличилась в разы и на данный момент в ней более 10000 контрагентов с разными адресами.
Очень часто контрагенты располагаются на одной улице но в разных домах, скажем ул. Комсомола, 12 и ул. Комсомола, 14, TextSimilarity считает это 100% совпадением, но это не так.
Как настроить более точно и тонко поиск по адресу.
Спасибо

ЗЫ. Программирования касался косвенно поэтому прошу объяснить более доступно.

К сообщению приложен файл:

011014.xlsm
(69.8 Kb)

Сообщение отредактировал biokirСреда, 01.10.2014, 14:47

 

Ответить

Формуляр

Дата: Среда, 01.10.2014, 22:41 |
Сообщение № 7

Группа: Друзья

Ранг: Ветеран

Сообщений: 832


Репутация:

255

±

Замечаний:
0% ±


Excel 2003, 2013

Вставил более свежую версию FindBestMatchTxt().
Добавлено сравнение цифр и фрагментов короче 2-х символов.
Сравнение стало точнее, не уверен, правда, что от этого лучше.
Но со скоростью сложнее…
В качестве слабой меры можно убрать условное форматирование и пресчёт TextSimilarity().
Давно подбирался к задаче сравнения адресов через индексирование по справочникам.
Сейчас довольно занят. В течение недели что-нибудь придумаем.

К сообщению приложен файл:

011014.zip
(62.8 Kb)


Excel 2003 EN, 2013 EN

Сообщение отредактировал ФормулярСреда, 01.10.2014, 22:45

 

Ответить

biokir

Дата: Четверг, 02.10.2014, 10:19 |
Сообщение № 8

Группа: Пользователи

Ранг: Новичок

Сообщений: 10


Репутация:

0

±

Замечаний:
0% ±


Excel 2010

Формуляр,
Александр, спасибо. Буду тестировать.

Изменил значение F=0 на F=0.2 результат улучшился.

Сообщение отредактировал biokirЧетверг, 02.10.2014, 10:52

 

Ответить

Формуляр

Дата: Четверг, 02.10.2014, 11:14 |
Сообщение № 9

Группа: Друзья

Ранг: Ветеран

Сообщений: 832


Репутация:

255

±

Замечаний:
0% ±


Excel 2003, 2013

biokir,
ну тогда попробуйте F=1.

Ещё вопросы:
База сравнения, значит, порядка 10000, а какой длины обрабатываемый список на 1ом листе?
Нужно ли его каждый раз обрабатывать целиком?
Или в него добавляются отдельные записи и всё пересчитывать не нужно?


Excel 2003 EN, 2013 EN

 

Ответить

biokir

Дата: Пятница, 03.10.2014, 09:51 |
Сообщение № 10

Группа: Пользователи

Ранг: Новичок

Сообщений: 10


Репутация:

0

±

Замечаний:
0% ±


Excel 2010

Формуляр,
F=1 пробовал все вернулось к первоначальной проблеме, остановился на 0.2, так как это оптимально.

Ответы:
Список бывает и больше самой базы.
Каждый раз он обрабатывается целиком.
Пересчитывать необходимо каждый раз по новому (специфика работы).

Александр, нашел на форуме еще одно Ваше творение SimTextX, там проводится поиск по аббревиатурам и это здорово, так как у меня тоже есть похожие проблемы.
Вчера тестировал на базе и столкнулся с тем, что в списках бывает несколько контрагентов расположенных по одному и тому же адресу, но наименование их разные.
Попробовал сцепить наименование и адрес, но результат только ухудшился. При сравнении отдельно адреса и наименования ничего не изменилось, только увеличилось время на обработку.
Как можно сделать так чтобы первостепенно проверялся адрес, при нахождении нужного проверялось наименование контрагента как в SimTextX.
Кстати столкнулся еще с такой вещью, после обработки списка при выполнении в нем манипуляций с фильтрами он пересчитывается заново, мне кажется было бы удобнее добавить «баттончик» при клике на который производилась операция сверки посредством макроса.
Как думаете?

 

Ответить

Формуляр

Дата: Суббота, 04.10.2014, 08:31 |
Сообщение № 11

Группа: Друзья

Ранг: Ветеран

Сообщений: 832


Репутация:

255

±

Замечаний:
0% ±


Excel 2003, 2013

столкнулся с тем, что в списках бывает несколько контрагентов расположенных по одному и тому же адресу, но наименование их разные.

Будем решать проблемы в порядке поступления. В принципе, если база упорядочена по адресам, можно отслеживать число повторов и в них потом искать по наименованию.

после обработки списка при выполнении в нем манипуляций с фильтрами он пересчитывается заново, мне кажется было бы удобнее добавить «баттончик» при клике на который производилась операция сверки посредством макроса.

Мысль абсолютно правильная. На больших объёмах я так обычно и делаю. Можно, впрочем, просто отключить автоматический пересчёт.


Excel 2003 EN, 2013 EN

 

Ответить

Формуляр

Дата: Воскресенье, 05.10.2014, 15:14 |
Сообщение № 12

Группа: Друзья

Ранг: Ветеран

Сообщений: 832


Репутация:

255

±

Замечаний:
0% ±


Excel 2003, 2013

biokir,
Стоит отметить, что база адресов поддерживается в весьма аккуратном состоянии. (Если не считать хаотически разбросанных включений типа «НЕТ ТЕРРИТОРИАЛЬНОГО ОТДЕЛЕНИЯ»).
Но, с точки зрения формального поиска, в ней много лишних «букав», которые не только съедают вычислительные ресурсы, но и снижают точность сравнения.
Я написал UDF, которая оставляет только «уличную» часть адреса, её и будем использовать при индексировании списка.
[vba]

Код

Public Function StreetAdr(adrStr As String) As String
     StreetAdr = Trim$(Mid$(adrStr, InStrRev(adrStr, «,», InStrRev(adrStr, «д.») — 3) + 1, 99))
End Function

[/vba]
Прошу обработать ею весь ст-ц C вашей базы, экспортировать в обычный текстовый формат, зазиповать и выложить. Думаю, в 100К должно уместиться. Если не влезет, выложите, сколько получится. Мне это нужно для отладки на реальном объёме с реальнной спецификой данных.


Excel 2003 EN, 2013 EN

 

Ответить

biokir

Дата: Понедельник, 06.10.2014, 13:45 |
Сообщение № 13

Группа: Пользователи

Ранг: Новичок

Сообщений: 10


Репутация:

0

±

Замечаний:
0% ±


Excel 2010

Формуляр,
Александр, добрый день!

Попробую, сейчас завалили работой, пока не когда.

Оставить только улицу для того чтобы сэкономить ресурсы это правильно, но как же быть с городом, ведь контрагенты в разных городах. А как знаешь ул. Ленина есть в каждом городе РФ :)

К сообщению приложен файл:

3570348.zip
(45.6 Kb)

Сообщение отредактировал biokirПонедельник, 06.10.2014, 14:39

 

Ответить

Формуляр

Дата: Понедельник, 06.10.2014, 21:00 |
Сообщение № 14

Группа: Друзья

Ранг: Ветеран

Сообщений: 832


Репутация:

255

±

Замечаний:
0% ±


Excel 2003, 2013

Ну я же не предлагаю уничтожить их как класс.
Просто для поиска они ни к чему, тем более выяснилось, что могут быть контрагенты с абсолютно одинаковыми адресами.
Тут хоть Ленина, хоть Тюленинина, придётся 2ым слоем по названию искать.


Excel 2003 EN, 2013 EN

Сообщение отредактировал ФормулярПонедельник, 06.10.2014, 21:00

 

Ответить

biokir

Дата: Вторник, 07.10.2014, 13:06 |
Сообщение № 15

Группа: Пользователи

Ранг: Новичок

Сообщений: 10


Репутация:

0

±

Замечаний:
0% ±


Excel 2010

Формуляр,
Александр, понятно что контрагенты с абсолютно одинаковыми адресами, не получится ли так что контрагент на улице Тюленина 1 в городе Н и на той же улице в городе М будет иметь один адрес по улице, но разный по городам… Или ты хочешь делать все последовательно, город, улица, дом, наименование.

 

Ответить

Формуляр

Дата: Вторник, 07.10.2014, 21:50 |
Сообщение № 16

Группа: Друзья

Ранг: Ветеран

Сообщений: 832


Репутация:

255

±

Замечаний:
0% ±


Excel 2003, 2013

biokir,
абсолютной гарантии быть, конечно, не может, но мне кажется, вероятность полного совпадения и «уличной части» адреса и названия контрагента пренебрежимо мала.
По крайней мере, значительно меньше вероятности всех прочих ошибок, которые всё равно придётся контролировать и исправлять руками.


Excel 2003 EN, 2013 EN

Сообщение отредактировал ФормулярВторник, 07.10.2014, 21:51

 

Ответить

Формуляр

Дата: Среда, 08.10.2014, 15:52 |
Сообщение № 17

Группа: Друзья

Ранг: Ветеран

Сообщений: 832


Репутация:

255

±

Замечаний:
0% ±


Excel 2003, 2013

Ну вот, в первом приближении готово.
Работает быстро, но не точно! :D :D :D

Пришлось пожертвовать попарным сравнением слов ради скорости.
Проверяйте пока на общую пригодность, а я точность ещё подтяну.


Excel 2003 EN, 2013 EN

 

Ответить

biokir

Дата: Среда, 08.10.2014, 16:38 |
Сообщение № 18

Группа: Пользователи

Ранг: Новичок

Сообщений: 10


Репутация:

0

±

Замечаний:
0% ±


Excel 2010

Формуляр,
Александр, ожиданный результат в принципе))))
Может не будем думать о времени обработки пока, и вернем в адрес город. А то в противном случае мне придется не только нашу базу причесывать, но и базу которая необходимо проверить (пришедшую).

убирать форму собственности нельзя, так как есть много контрагентов отличающихся только этой формой.
Например:
ООО Стоматология №1
ОАО Стоматология №1
МУЗ Стоматология №1
ЗАО Стоматология №1
и это не предел

 

Ответить

Формуляр

Дата: Среда, 08.10.2014, 16:58 |
Сообщение № 19

Группа: Друзья

Ранг: Ветеран

Сообщений: 832


Репутация:

255

±

Замечаний:
0% ±


Excel 2003, 2013

Может не будем думать о времени обработки пока, и вернем в адрес город.

Город — вернём. На следующем этапе. Но в ином виде.

убирать форму собственности нельзя, так как есть много контрагентов отличающихся только этой формой.

И что, у них при этом совпадает «уличный» адрес?
Сравнение по названию происходит после поиска по адресу.
К тому же, я писал «за исключением случаев, когда она является дифференцирующим признаком.» В 99% случаев это не так.
Я, при этом, говорю про столбец базы, по которому производится поиск. Никто не запретит иметь в той же таблице други ст-цы с любой бесполезной или полезной информацией.


Excel 2003 EN, 2013 EN

Сообщение отредактировал ФормулярСреда, 08.10.2014, 17:01

 

Ответить

biokir

Дата: Среда, 08.10.2014, 17:03 |
Сообщение № 20

Группа: Пользователи

Ранг: Новичок

Сообщений: 10


Репутация:

0

±

Замечаний:
0% ±


Excel 2010

Формуляр,
Ну если вернем, то я спокоен :)

И что у них при этом совпадает «уличный» адрес?

Ситуации бывают такие, что контрагент имел форму МУЗ, но потом изменил на ООО. У нас в базе исправлено, а в приходящей еще нет. А адреса совпадают и к сожалению таких не маленький процент.

 

Ответить

Оригинальный официальный аккаунт WeChat

Система: Windows 7
Программное обеспечение: Excel 2010 / Access 2010

  • Новая глава в этой серии, посвященная базе данных Access.
  • Основной фрейм: Excel как рабочий интерфейс, Access как база данных
  • Поговорим о нечетком запросе сегодня
  • Вовлеченные знания:ADOSQL:like

Часть 1: Цель

Список товаров
1.png

  1. в соответствии сИдентификатор товараНайдите необходимые продукты
  2. Реализовано нечетким поиском, немногоBaiduВкус, знать только часть информации, чтобы узнать
  3. Логический процесс
    • Подключиться к базе данных
    • Определите оператор SQL в соответствии с потребностями
    • Выполните инструкцию SQL, получитеrecordset
    • будуrecordsetЗапишите в рабочий лист (название поля + все записикоторый Название столбца + каждая строка)
    • Отключиться от базы данных
  4. ПоискИдентификатор товараПервая букваmпродукт

Часть 2: Код

Sub test()
    Dim cnn As New ADODB.Connection 'связь
    Dim rs As New ADODB.Recordset
    Dim SQL As String
    Dim tblName
    Dim dbAddr

    dbAddr = ThisWorkbook.Path & " Product List.accdb"
    tblName = "Список продуктов"

    'Подключиться к базе данных
    With cnn
        .Provider = "Microsoft.ACE.OLEDB.12.0"
        .Open "Data Source=" & dbAddr
    End With

    opFilds = «Код товара, название товара, производитель, количество»
    searchC = «Идентификатор продукта вроде'm% '»

    SQL = "Select " & opFilds & " from " & tblName & " where (" & searchC & ")"
    Set rs = cnn.Execute(SQL)

    Dim sht
    Dim fildNum

    Set sht = ThisWorkbook.Worksheets("Пример")
    sht.Cells.ClearContents

    fildNum = rs.Fields.Count
    For j = 0 To fildNum - 1 Step 1
        fildName = rs.Fields(j).Name
        sht.Cells(1, j + 1) = fildName
    Next j

    sht.Cells(2, 1).CopyFromRecordset rs

    cnn.Close
    Set rs = Nothing
    Set cnn = Nothing

End Sub

Скриншот кода
3.png

Результаты
2.png

Часть 3: Часть интерпретации кода

  1. Выберите идентификатор продукта, название продукта, производителя, количество из списка продуктов, где (идентификатор продукта, например 'm%')
  2. Толкование на китайском: выберите встречуИдентификатор товараПервая цифра — это буква м с информацией о продукте. В результатеБез различияДело
  3. Такой%Представляет 0 или любой символ, немного похожий на*Роль

Часть 4: Расширение

  1. _Представляет одиночный символ,searchC = "Идентификатор продукта, например '____'"Четыре символа подчеркивания, Результаты приведены ниже

4.png

  1. []Укажите диапазон,searchC = "Идентификатор продукта, например '[0-9]%'", Что означает строку, начинающуюся с 0-9, результат будет следующим

5.png

  1. [ ]Укажите диапазон,searchC = "Идентификатор продукта, например '[a-z]%'", Представляет строку, начинающуюся с букв a-z, без учета регистра, результат будет следующим

6.png

  1. [!]За пределами указанного диапазона,searchC = "Идентификатор продукта, например '[! a-z]%'", Что означает, что он не начинается с a-z, результат будет следующим
    8.png

  2. not likeОтрицать,searchC = "Идентификатор продукта не похож на '[a-z]%'", Представляет строку, начинающуюся с букв a-z, без учета регистра, результат будет следующим

7.png


Эта статья — оригинальная работа, если вам нужно перепечатать, вы можете добавить аккаунт редактора WeChat.learningBin

Выше приведены учебные материалы, увидимся в следующий раз

Если будут обнаружены какие-либо ошибки, пожалуйста, оставьте сообщение, чтобы указать


Еще интереснее, обратите внимание на публичный аккаунт WeChat
Отсканируйте QR-код и подпишитесь на этот официальный аккаунт

 .jpg

Понравилась статья? Поделить с друзьями:
  • Vba несколько книг excel в одну
  • Vba не работает excel только
  • Vba не переходит к word
  • Vba не могу открыть книгу excel
  • Vba не заменяет текст в word