Может ли автофильтр принимать как инклюзивные, так и неинклюзивные подстановочные знаки из ключей словаря?

Я искал способ отфильтровать электронную таблицу Excel с более чем двумя подстановочными знаками. Ранее я спрашивал в StackOverflow, могу ли я напрямую ввести более двух подстановочных знаков в AutoFilter в VBA вместо использования расширенного фильтра на листе, поскольку мои макросы в основном используются через сценарии PowerShell, которые пропускают ввод. Эти подстановочные знаки используются для фильтрации различных электронных таблиц, и результат сохраняется.

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

Теперь я хочу расширить это, чтобы передавать более конкретные подстановочные знаки, которые я хочу исключить. Скажем, например, я хочу включить «A*» и «B*», но не «BB*», чтобы, например, «BA*» все еще был там. Может ли приведенный ниже макрос работать с прохождением ‹>BB*?

hierArray всегда содержит только список простых строк, состоящий максимум из 10 (но редко более 3 символов).

Public Function multiHier(hierArray As Variant)

Dim v As Long, vVALs As Variant, dVALs As Object
Dim colNum As Long, hierLen As Integer, hier As Variant
Dim rng As Range

Set dVALs = CreateObject("Scripting.Dictionary")
dVALs.comparemode = vbTextCompare
colNum = Application.Match("*ierarchy*", Range("A1:Z1"), 0)

With Worksheets(1)
    'If .AutoFilterMode Then .AutoFilterMode = False

    With .Cells(1, 1).CurrentRegion
        vVALs = .Columns(colNum).Cells.Value2

        For v = LBound(vVALs, 1) To UBound(vVALs, 1)
            If Not dVALs.exists(vVALs(v, 1)) Then

                For Each hier In hierArray
                    hierLen = Len(hier)

                    Select Case UCase(Left(vVALs(v, 1), hierLen))
                        Case hier
                            dVALs.Add Key:=vVALs(v, 1), item:=vVALs(v, 1)
                        Case Else
                   End Select

               Next hier
            End If
        Next v

        If CBool(dVALs.Count) Then
            'populated the dictionary; now use the keys
            .AutoFilter Field:=colNum, Criteria1:=dVALs.keys, Operator:=xlFilterValues

            Set rng = Worksheets(1).AutoFilter.Range
            multiHier = rng.Columns(1).SpecialCells(xlCellTypeVisible).Count - 1
        Else
            multiHier = 0
        End If

    End With

End With

dVALs.RemoveAll: Set dVALs = Nothing

End Function

person Chris    schedule 05.01.2016    source источник
comment
Итак, hierArray будет чем-то вроде hierArray = Array("A•", "B•", "<>BB•") ...?   -  person    schedule 05.01.2016
comment
На данный момент массив выглядит просто как hierArray = Array(A,B,CC) и т.д. Но благодаря макросу работает как подстановочный знак. Если просто добавить ‹› к тем, кто его исключил, у меня это отлично работает. Предполагалось, что это будет не так просто!   -  person Chris    schedule 05.01.2016
comment
Этого не произойдет, но метод, используемый для создания строки, должен быть доработан, чтобы написать код, который анализирует строку и преобразует ее в рабочие операции.   -  person    schedule 05.01.2016
comment
Истинный. Массив, похожий на (A,B,!BB) или (A,B,‹›BB) и т. д., мне не слишком дорог.   -  person Chris    schedule 05.01.2016


Ответы (1)


Я собираюсь придерживаться префикса ! для сброса, так как это один символ.

    Dim h As Long, hstr As String   'put these at the top with the other var declarations

    For v = LBound(vVALs, 1) To UBound(vVALs, 1)
        For h = LBound(hierArray) To UBound(hierArray)   'I just prefer to work this way
            hstr = hierArray(h) & Chr(42)   'stick a * on the end
            If Left(hstr, 1) = Chr(33) And LCase(vVALs(v, 1)) Like LCase(Mid(hstr, 2)) Then     'starts with a ! and pattern matches the value
                'matched a discard pattern. check to see if it was previously added
                If dVALs.Exists(vVALs(v, 1)) Then _
                    dVALs.Remove vVALs(v, 1)    'get rid of it
                Exit For  'discarded. do not keep checking to add
            ElseIf LCase(vVALs(v, 1)) Like LCase(hstr) Then
                If NOT dVALs.Exists(vVALs(v, 1)) Then _
                    dVALs.Add Key:=vVALs(v, 1), Item:=vVALs(v, 1)
            End If
        Next h
    Next v

При создании строки hierArray вы можете сэкономить несколько циклов, поместив сначала шаблоны отбрасывания. Таким образом, они не будут добавлены, а затем удалены.

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

person Community    schedule 05.01.2016
comment
Отлично, спасибо - попробуем. Моя единственная проблема, которую я сначала отбрасываю, что, если нужно что-то вроде ABA, ABB, ABX, но не ABC? Разве не имеет смысла сопоставлять AB, а затем специально исключать ABC? - person Chris; 05.01.2016
comment
Это действительно будет зависеть от количества возможных совпадений для каждого сценария, но если вы сначала отбрасываете, то не пробуете другие совпадения. Вы можете сопоставить AB, а затем отбросить ту же запись с !ABC позже. Если ABC отбрасывается первым, он выходит из цикла (не продолжает попытки добавления), поэтому оставшиеся циклы не выполняются. - person ; 05.01.2016
comment
Я проверил вышеизложенное и получил Run-time error '457': This key is already associated with an element of this collection, указывающий на строку dVALs.Add Key:=vVALs(v, 1), item:=vVALs(v, 1). Я тестировал это с исключением и без него. - person Chris; 06.01.2016
comment
Мои тестовые данные не имели дубликатов в пределах потенциальных совпадений. Я добавил одну строку кода, чтобы компенсировать это. - person ; 06.01.2016
comment
можно ли изменить этот макрос так, чтобы код запускался, если он просто получит 1 ключ? он ожидает массив (или вариант, который всегда имеет тенденцию быть массивом, но может быть одной строкой), поэтому в настоящее время он не соответствует. Он падает при проверке верхней/нижней границы, я не уверен, как обойти это только для 1 элемента. - person Chris; 18.08.2016