Фильтрация блока по атрибуту после того, как я уже отфильтровал по другому

Я создаю консоль, которая находит блоки с определенным значением атрибута и заменяет его другим (аналогично поиску (текстовое поле1) и замене (текстовое поле2) в Word).

For Each blk In ss
        If (blk.HasAttributes) Then
            attr = blk.GetAttributes()
            For i = 0 To UBound(attr)
                If attr(i).TagString = "item" And _
                    attr(i).TextString = TextBox1.Value Then
                    attr(i).TextString = TextBox2.Value
                    Exit For
                End If
            Next
            End If
    Next

Хотя я решил это, возникла новая проблема. Мои коллеги теперь хотят фильтровать по 2 атрибутам. Например, атрибут с тегом «предмет» может иметь значение «кола». Но вы можете изменить только название блоков, содержащих газировку, а не лекарство. Таким образом, я выбрал еще один атрибут, который их различает (textbox11).

For Each blk In ss
        If (blk.HasAttributes) Then
            attr = blk.GetAttributes()
            For i = 0 To UBound(attr)
            If attr(i).TagString = "origin" And attr(i).TextString = TextBox11.Value Then
            attr = 0
            attr = blk.GetAttributes()

            For o = 0 To UBound(attr)
                If attr(i).TagString = "item" And _
                    attr(i).TextString = TextBox1.Value Then
                    attr(i).TextString = TextBox2.Value
                    Exit For
                End If
                End If
            Next
            End If
    Next

Но это не работает. Как бы вы подошли к проблеме?


person Pedro    schedule 21.11.2019    source источник
comment
Вам нужно использовать индентор, чтобы отступы были одинаковыми. Это ненормально, что у вас есть End If дважды на одном и том же уровне отступа ;-)   -  person Mathieu Guindon    schedule 21.11.2019


Ответы (1)


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

Dim flg As Boolean
Dim idx As Long

For Each blk In ss
    If blk.HasAttributes Then
        attr = blk.GetAttributes()
        flg = False
        idx = -1
        For i = 0 To UBound(attr)
            Select Case attr(i).TagString
                Case "origin"
                    If attr(i).TextString = TextBox11.Value Then flg = True
                Case "item"
                    idx = i
            End Select
        Next i
        If flg And idx >= 0 Then
            If attr(idx).TextString = TextBox1.Value Then
                attr(idx).TextString = TextBox2.Value
            End If
        End If
    End If
Next blk

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

Вы можете немного повысить эффективность для блоков со многими атрибутами, проверяя значения flg и idx на каждой итерации цикла for и выходя из цикла for, если они содержат соответствующие значения, или, альтернативно, вы можете использовать цикл Do или While, который проверяет эти переменные на каждой итерации (вместе с величиной переменной i), чтобы избежать использования Exit; но я должен представить, что улучшение производительности будет незначительным в обоих случаях.

person Lee Mac    schedule 21.11.2019
comment
большое спасибо, все работает :) только что нашел это недостающее If flg And idx >= 0 Then я полагаю, вы имеете в виду If flg=true And idx >= 0 Then спасибо за советы! - person Pedro; 26.11.2019
comment
Пожалуйста. flg = True не требуется, так как flg = True вернет True или False, которые являются единственными значениями, которые может принимать flg. - person Lee Mac; 26.11.2019