Форум программистов, компьютерный форум, киберфорум
VBA
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.73/26: Рейтинг темы: голосов - 26, средняя оценка - 4.73
 Аватар для Султанов
54 / 39 / 3
Регистрация: 25.01.2013
Сообщений: 368

Не всегда срабатывает пользовательская функция

22.10.2014, 14:41. Показов 5610. Ответов 36
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день!
Слепил из имеющихся в инете функций Vlookup и FindSame пользовательскую функцию ВПР2 под свои нужды, посадил в модуль, но как то через раз она не работает, результат значения по нулям.

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
Public Function ВПР2(Диапазон As Variant, ПозСтолб As Variant, ИскЗнач As Variant, _
НомПоз As Variant, РезСтолб As Variant, Optional ByVal ФлагПоз As Variant = 0)
    Application.Volatile True
    Dim i As Long, iCount As Long
       ''полное совпадение
       If ФлагПоз = 0 Then
    Select Case TypeName(Диапазон)
    Case "Range"
        For i = 1 To Диапазон.Rows.Count
            If Диапазон.Cells(i, ПозСтолб) = ИскЗнач Then
                iCount = iCount + 1
            End If
            If iCount = НомПоз Then
                ВПР2 = Диапазон.Cells(i, РезСтолб)
                Exit For
            End If
        Next i
    Case "Variant()"
        For i = 1 To UBound(Диапазон)
            If Диапазон(i, ПозСтолб) = ИскЗнач Then iCount = iCount + 1
            If iCount = НомПоз Then
                ВПР2 = Диапазон(i, РезСтолб)
                Exit For
            End If
        Next i
    End Select
       End If
''частично приблеженное совпадение
If ФлагПоз <> 0 Then
Select Case TypeName(Диапазон)
    Case "Range"
        For i = 1 To Диапазон.Rows.Count
            If Equality(Диапазон.Cells(i, ПозСтолб), ИскЗнач) > eqmax Then
            temp = Диапазон.Cells(i, РезСтолб)
            iCount = iCount + 1
            eqmax = Equality(Диапазон.Cells(i, ПозСтолб), ИскЗнач)
            If eqmax < ФлагПоз Then temp = Empty
            End If
            If iCount = НомПоз Then
               iCount = Empty
               ВПР2 = temp
            End If
        Next i
    Case "Variant()"
        For i = 1 To UBound(Диапазон)
            If Equality(Диапазон(i, ПозСтолб), ИскЗнач) > eqmax Then
            temp = Диапазон(i, РезСтолб)
            iCount = iCount + 1
            eqmax = Equality(Диапазон(i, ПозСтолб), ИскЗнач)
            If eqmax < ФлагПоз Then temp = Empty
            End If
            If iCount = НомПоз Then
               iCount = Empty
               ВПР2 = temp
            End If
        Next i
    End Select
       End If
   
End Function
Private Function Equality(t1 As Variant, t2 As Variant) As Integer
Equality = 0
    For n = 1 To Len(t1)
        For k = n To Len(t1)
            s = Mid(t1, n, k)
            s1 = "*" & s & "*"
            If t2 Like s1 Then
                If (k - n + 1) > Equality Then Equality = k - n + 1
            End If
        Next k
    Next n
End Function
Посмотрите пожалуйста, что то наверное я не так сделал
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
22.10.2014, 14:41
Ответы с готовыми решениями:

В EXCEL не всегда срабатывает функция СУММЕСЛИ
Функция ПОИСК ( FIND ) находит данные, а вот СУММЕСЛИ не находит. Во вложенном Екселе такие &quot;ненайденные&quot; данные окрашены...

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

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

36
 Аватар для Султанов
54 / 39 / 3
Регистрация: 25.01.2013
Сообщений: 368
23.10.2014, 18:20  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от KoGG Посмотреть сообщение
Существенна разница в типе аргументов функции, если это настоящий Range, а не символьная переменная, то и пользовательская функция будет работать по другому.
речь идет про чтение с листа в сравнении с чтением в массив?
Цитата Сообщение от KoGG Посмотреть сообщение
Лучше делать ссылку на файл, закрыть файл источник а потом копировать строку в ячейку для аргумента, отрезав "=". Проблемы добавляют апострофы. Если имена путей, файлов и листов не содержат пробелы, дефисы, лишние точки, то можно обойтись без них.
... так как быть?!
Цитата Сообщение от KoGG Посмотреть сообщение
Функция Equality очень медленная, если сравнивать только начальные части символьных переменных, от 1 до ФлагПоз, то все будет работать в разы быстрее.
так ведь при ФлагПоз при умолчании 0 не вижу шустроты,

Добавлено через 10 минут
проблема у меня в том что при смене связи, выдает ошибку функции ... и коллегам теперь сказать что труд будет облегчен....., а ведь хотел как лучше
0
 Аватар для KoGG
5730 / 1633 / 419
Регистрация: 23.12.2010
Сообщений: 2,455
Записей в блоге: 1
24.10.2014, 09:47
1 . Речь идет про объект. Иначе это просто символьная строка, при закрытом файле источнике символьная строка не позволяет восстановить доступ к объекту. Ну и много всего прочего.
2. Как хочется. Для оптимизации - лучше отойти от начального замысла и делать зеркальные листы. Комментарий дан для теории.
3 . Так при ФлагПоз=0 Equality не задействована. Это замедление даст себя знать при приблизительном поиске.
Общее замедление зависит от количества функций ВПР2 на листе и в книге. Так как "Application.Volatile True" они пересчитываются все многократно.
4. Архитектуру взаимодействия и работы с файлами надо продумывать до начала программирования. Частая смена связей тоже не лучшее решение. Лучше делать файл, в котором хоть 40 зеркальных листов, но чтобы положение источников всегда было строгим - в определенной сетевой папке. Еще лучше - когда названия файлов стандартизированы.
0
 Аватар для Султанов
54 / 39 / 3
Регистрация: 25.01.2013
Сообщений: 368
24.10.2014, 12:19  [ТС]
Цитата Сообщение от KoGG Посмотреть сообщение
Архитектуру взаимодействия и работы с файлами надо продумывать до начала программирования. Частая смена связей тоже не лучшее решение.
KoGG, решение думаю организовать считывание данных на новый лист как значение, чем делать ссылки.
Не подскажите как организовать выбор листов источника -файла, после выбора нужного файла ч/з Application.FileDialog(msoFileDialogOpen ) , затем в новом листе выложить данные и дать диапазону имя, чтобы в функции не менять наименование диапазона
0
 Аватар для KoGG
5730 / 1633 / 419
Регистрация: 23.12.2010
Сообщений: 2,455
Записей в блоге: 1
24.10.2014, 13:44
Ну тогда легче файл все равно открыть. Надо делать пользовательскую форму, из открытого файла добавлять в ListBox имена листов. Но как то все криво.
0
 Аватар для Султанов
54 / 39 / 3
Регистрация: 25.01.2013
Сообщений: 368
24.10.2014, 23:01  [ТС]
Цитата Сообщение от KoGG Посмотреть сообщение
Но как то все криво.
Так при изменении связей порою виснет

Добавлено через 8 часов 57 минут
KoGG, у меня есть просьба к Вам, по данной теме Вы писали что Evaluate() у Вас работает, можете пример с использованием совместно функцией ВПР2, у меня выдает как Error 2015
0
 Аватар для KoGG
5730 / 1633 / 419
Регистрация: 23.12.2010
Сообщений: 2,455
Записей в блоге: 1
27.10.2014, 10:04
Если адрес диапазона вводим в ячейке, то два апострофа впереди, а третий перед "!" ( этот всегда там).
Файл источник - Книга1.xls должна быть открыта.
Вложения
Тип файла: rar ВПР2_прим.rar (17.4 Кб, 9 просмотров)
1
 Аватар для Султанов
54 / 39 / 3
Регистрация: 25.01.2013
Сообщений: 368
30.10.2014, 14:07  [ТС]
KoGG, если я не отниму у Вас времени, хотелось бы на данной функции ВПР2 увеличить передачу неопределенного количества аргументов в той же последовательности поскольку надо использовать 2 или даже 4 критерия отбора в зависимости от использования, но только для процедуры возможно использование Paramarray, не покажите как это сделать?
Или надо от количества критериев поиска, делать ВПР3 и т.д.

При использовании функции столкнулся со следующей проблемой, при поиске приближенного слова "Акмолинский ОДРТ" в сравнении допустим "Акмолинская ОДРТ" и "Алматинская ОДРТ", или "ИТОГО по Акмолинской ОДРТ" выдает где одинаково а где разные результаты, понятно что при глубине поиска ФлагПоз это очевидно, у всех один корень, но как построит алгоритм:
1 Разбить предложения на слова (массив) Split, не факт что могут встретятся иные спец. символы кроме пробела
2. Использовать Instr или все таки Equality по самому длинному элементу
3. Или каждый элемент массива прогнать через Like
Подскажите, пожалуйста, на каком нибудь примере

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

Добавлено через 4 минуты
подскажите какой нибудь алгоритм, в подмогу для работы
0
 Аватар для KoGG
5730 / 1633 / 419
Регистрация: 23.12.2010
Сообщений: 2,455
Записей в блоге: 1
31.10.2014, 09:44
Вместо ParamArray можно использовать Опциональные аргументы, которые можно оставлять пустыми.
Короткий пример здесь не поможет.
Надо предварительно обрабатыватьи шаблон поиска и массив сравнения, делая замены всех возможных окончаний, "ский" и "ская" на "ск"; удаляя слова паразиты "ИТОГО" и т.п. (если надо), заменяя все нестандартные символы на " ", а затем все двойные пробелы несколько раз на одинарные. Сравнивать уже стандартизированные строки, начиная слева на ФлагПоз.
Вот процедурка, сортирующая слова в массиве, от самого длинного до самого короткого, а одинаковой длины по афавиту (может пригодится).
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Option Compare Text
Sub Sort_Words(S)
    If Not IsArray(S) Then Exit Sub
    If UBound(S) < 1 Then Exit Sub
    Dim i%, j%, Ma%, L%(), tS
    ReDim L(UBound(S))
    For i = LBound(S) To UBound(S)
        L(i) = Len(S(i))
    Next i
    For i = LBound(S) To UBound(S)
        Ma = L(i)
        For j = i + 1 To UBound(S)
            If Ma < L(j) Or (Ma = L(j) And S(i) > S(j)) Then
                Ma = L(j)
                L(j) = L(i)
                L(i) = Ma
                tS = S(j)
                S(j) = S(i)
                S(i) = tS
            End If
        Next j
    Next i
End Sub
Потом можно сравнивать например самые длинные слова в массивах, разбитых Split, или все слова в упорядоченных массивах, определяя количество совпавших символов, к общему колическтву символов без пробелов наиболее короткого набора слов и вабрать критерий совпадения например >=0.85
0
 Аватар для Султанов
54 / 39 / 3
Регистрация: 25.01.2013
Сообщений: 368
02.11.2014, 07:41  [ТС]
Цитата Сообщение от KoGG Посмотреть сообщение
Вместо ParamArray можно использовать Опциональные аргументы, которые можно оставлять пустыми.
Короткий пример здесь не поможет.
если опционально по 3 критериям сравнивать только одно, то как расписать чтобы алгоритм пропустил 2 других, которые имеют значение Empty

Visual Basic
1
2
3
4
Public Function ВПРM(Диапазон As Variant, РезСтолб As Variant, Optional ByVal ФлагПоз As Variant = 0, _
Optional ByVal ПозСтолб1 As Variant, Optional ByVal ИскЗнач1 As Variant, _
Optional ByVal ПозСтолб2 As Variant, Optional ByVal ИскЗнач2 As Variant, _
Optional ByVal ПозСтолб3 As Variant, Optional ByVal ИскЗнач3 As Variant)
Visual Basic
1
2
3
4
5
6
7
8
9
 If ФлагПоз = 0 Then
        For i = 1 To UBound(Диапазон2)
            If Диапазон2(i, ПозСтолб1) = ИскЗнач1 Then
            If Диапазон2(i, ПозСтолб2) = ИскЗнач2 Then
            If Диапазон2(i, ПозСтолб3) = ИскЗнач3 Then
                    ВПРM = Диапазон2(i, РезСтолб)
                    Exit For
            End If: End If: End If
        Next i
Добавлено через 8 часов 4 минуты
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 If ФлагПоз = 0 Then
        For i = 1 To UBound(Диапазон2)
            If IsEmpty(ПозСтолб1) Then
            Диапазон2(i, ПозСтолб1) = Empty: ИскЗнач1 = Empty
            End If
            If IsEmpty(ПозСтолб2) Then
            Диапазон2(i, ПозСтолб2) = Empty: ИскЗнач2 = Empty
            End If
            If IsEmpty(ПозСтолб3) Then
            Диапазон2(i, ПозСтолб3) = Empty: ИскЗнач3 = Empty
            End If
                If Диапазон2(i, ПозСтолб1) & " " & Диапазон2(i, ПозСтолб2) _
                & " " & Диапазон2(i, ПозСтолб3) = ИскЗнач1 & " " & ИскЗнач2 & " " & ИскЗнач3 Then
                    ВПРM = Диапазон2(i, РезСтолб)
                    Exit For
                End If
        Next i
0
 Аватар для Султанов
54 / 39 / 3
Регистрация: 25.01.2013
Сообщений: 368
02.11.2014, 18:23  [ТС]
KoGG, поступил по Вашей рекомендации, но видимо наталкиваюсь на свои же ошибки в связи с плохим знанием приемов в VBA, и оптимизированных алгоритмов
Столкнулся со следующими ошибками
1. Не могу прописать алгоритм с пропуском пустых аргументов в функции
2. Отработка сравнения массива с массива/слова со словом
Вложения
Тип файла: rar ВПР2_97.rar (15.2 Кб, 7 просмотров)
0
 Аватар для Alex77755
11525 / 3812 / 683
Регистрация: 13.02.2009
Сообщений: 11,229
02.11.2014, 19:53
Visual Basic
1
 If IsMissing(Диапазон2(i, ПозСтолб1)) = IsMissing(ИскЗнач1) Then
такое равентсво будет верно и в случае когда оба параметра есть и в случае когда обоих параметров нет.
Надо же проверять, что бы оба были
Visual Basic
1
 If IsMissing(Диапазон2(i, ПозСтолб1)) And IsMissing(ИскЗнач1) Then
Добавлено через 1 минуту
Да и проверять же надо АРГУМЕНТЫ функции
Visual Basic
1
If IsMissing(ПозСтолб1) And IsMissing(ИскЗнач1) Then
Добавлено через 6 минут
блок для 1 пары
Visual Basic
1
2
3
4
5
            If Not IsMissing(ПозСтолб1) And Not IsMissing(ИскЗнач1) Then
            If Диапазон2(i, ПозСтолб1) = ИскЗнач1 Then
                    ВПРM = Диапазон2(i, РезСтолб)
                    Exit For
            End If: End If:
0
 Аватар для Alex77755
11525 / 3812 / 683
Регистрация: 13.02.2009
Сообщений: 11,229
02.11.2014, 20:16
набросал пример вызова функции с опциональными параметрами и без них
Вложения
Тип файла: rar Опция.rar (9.1 Кб, 7 просмотров)
0
 Аватар для Султанов
54 / 39 / 3
Регистрация: 25.01.2013
Сообщений: 368
03.11.2014, 10:19  [ТС]
KoGG, задача получилось длинной ч/з множества условий, а вот с массивами никак у меня не получилось
Посмотрите пожалуйста
Вложения
Тип файла: rar ВПР2_97.rar (18.1 Кб, 5 просмотров)
0
 Аватар для Султанов
54 / 39 / 3
Регистрация: 25.01.2013
Сообщений: 368
03.11.2014, 14:39  [ТС]
Проверил, вроде задуманное осуществляет, но есть ли возможность оптимизировать его
0
 Аватар для Султанов
54 / 39 / 3
Регистрация: 25.01.2013
Сообщений: 368
03.11.2014, 14:40  [ТС]
сам файл
Вложения
Тип файла: rar ВПР2_97.rar (20.8 Кб, 14 просмотров)
0
 Аватар для KoGG
5730 / 1633 / 419
Регистрация: 23.12.2010
Сообщений: 2,455
Записей в блоге: 1
05.11.2014, 17:10
Недостаточно комментариев, непонятна цель введения дополнительных параметров, так что существенно оптимизировать не могу.
А вот функцию Equality для приблизительных совпадений я переделал, теперь Sort_Words не нужен.
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Function QuickEquality(ByVal t1 As Variant, ByVal t2 As Variant) As Integer
    Dim i%, j%, k%, S, Z, L%, N1%, N2%
    Dim Max1%(), Max2%(), Sum%
    S = Split(t1, " "): Z = Split(t2, " ")
    N1 = UBound(S): N2 = UBound(Z)
    ReDim Max1(0 To N1), Max2(0 To N2)
    For i = 0 To N1
        L = Len(S(i))
        For j = 0 To N2
            For k = L To IIf(Max1(i) > 2, Max1(i), 2) Step -1
                If Left(S(i), k) = Left(Z(j), k) Then
                    If Max1(i) <= k And Max2(j) <= k Then Max1(i) = k: Max2(j) = k
                    Exit For
                End If
            Next
        Next j
        Sum = Sum + Max1(i)
    Next i
    QuickEquality = Sum
End Function
Sub test_aa()
    Debug.Print QuickEquality("Акт в Актюбинске", "Актюбинский Акт2 вот")
    Debug.Print QuickEquality("Акмолинский ОДРТ", "ИТОГО по Акмолинской ОДРТ")
    Debug.Print QuickEquality("Акмолинский ОДРТ", "Алматинская ОДРТ")
End Sub
1 и 2-х буквенные совпадения в начале слов - игнорируются.
1
 Аватар для Султанов
54 / 39 / 3
Регистрация: 25.01.2013
Сообщений: 368
06.11.2014, 17:42  [ТС]
Цитата Сообщение от KoGG Посмотреть сообщение
Недостаточно комментариев, непонятна цель введения дополнительных параметров, так что существенно оптимизировать не могу.
Функция должна возвращать один результат из максимально-возможных совпадений искомых значений (слов/слова) в зависимости от 1 до 3 критериев поиска, задаваемых пользователем, в противном случае если нет совпадений -ноль.
В функции попытался реализовать возврат значения ячейки по строке, 1) по точному совпадению слов/предложений 2) по самому длинному слову с максимальной схожестью 3) предложение с предложением по совпавшим по корню словам

Добавлено через 2 минуты
KoGG, дополнительные параметры это вы про аргументы?

Добавлено через 6 минут
KoGG,
Цитата Сообщение от Султанов Посмотреть сообщение
в зависимости от 1 до 3 критериев поиска, задаваемых пользователем
т.е при соблюдении всех условий задаваемых пользователей (от 1 до 3)

Добавлено через 1 минуту
сегодня выдала ошибку за №9 одна из функций, как отловить где она возникла?

Добавлено через 1 час 10 минут
KoGG, Константин спасибо! вопросы в вышеизложенном посте отпали

Добавлено через 22 часа 48 минут
KoGG, я уже не знаю как решить вопрос относительно функции, без того что многое только с вашей отзывчивостью и помощью решено по данному коду, могли бы вы заглянуть на тему Многократное вычисление функцией
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
06.11.2014, 17:42

Пользовательская функция
Здраствуйте! Помогите пожалуйста, Как создать пользовательскую функцию, которая по выбранному диапазону ячеек считала бы среднее значение...

Пользовательская функция
Помогите пожалуйста Физическое лицо имеет $x, €y, ₽z. Пересчитать общую сумму в рублях. Нужно написать пользовательскую функцию

Пользовательская функция с циклом
Function G(b) As Double If b = 1 Then 'проверка на начальные условия G = 1 End If If b = 0.5 Then 'проверка на...

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

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
37
Ответ Создать тему
Новые блоги и статьи
Саморегулирующийся социальный контракт для сервера cross-section.
Hrethgir 14.08.2026
С кодом конечно таких глубоких размышлений пока не было, впрочем я уже привык к алгоритмизации. Суть предмета записи: снова в диалоге с нейросетью (я взял пока себе ник для учётки админа - Rector). . . .
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru