Excel VBA удалить строку, где ячейка содержит строку поиска

Попытка просмотреть столбец в цикле, найти «Итого» в ячейках, которые также содержат другой текст (например, «Итог за январь», «Итог по Бостону», «Итог по офису», «Итого по компании ABC»), и удалить целые строки, где « Итого». Вот что у меня есть (r и rcell определены как объекты диапазона):

Set r = Range(Cells(4, "B"), Cells(LastRow, "B"))
For Each rcell In r
    If Not Excel.WorksheetFunction.Search("Total", rcell) = "#VALUE!" Then
    Rows(target.Row).Delete
    Else
    'do nothing
    End If
Next

Я пытаюсь следовать логике, которая гласит: «Если ячейка не содержит «Итого», она вернет ошибку. Итак, для всех ячеек, которые не возвращают ошибку, удалите строку». Мой синтаксис явно неверен. Я посетил ряд подобных вопросов здесь, на сайте, и не смог заменить рабочий код.

В стандартных формулах Excel это будет ЕСЛИ(ЕОШИБКА(ПОИСК(...))...).

Огромное спасибо за помощь.


person Ephs05msm    schedule 18.03.2014    source источник
comment
Другой подход. Включите средство записи макросов, отфильтруйте столбец по итоговому значению, удалите видимые строки, отключите средство записи макросов и отредактируйте полученный код.   -  person Doug Glancy    schedule 18.03.2014
comment
Спасибо, Дуг. Следуя предложенным вами шагам, был создан код с явным массивом, в котором перечислены все фильтруемые записи, что не похоже на то, что его можно сделать динамическим. Я не видел никакого кода, связанного с моим фильтром, основанным на поиске Total (что я и сделал во время записи, но результатом был вышеупомянутый массив). Я где-то ошибся?   -  person Ephs05msm    schedule 18.03.2014


Ответы (2)


На всякий случай, если вы вернетесь сюда, я подумал, что продемонстрирую, что я имел в виду в своем комментарии. Это правда, что средство записи макросов создает буквальный массив всех значений, содержащих «Всего». Готов поспорить, ваш сгенерированный код выглядел примерно так:

Sub Macro1()
    ActiveSheet.Range("$B$3:$B$29").AutoFilter Field:=1, _
    Criteria1:=Array("Boston Total", "Chicago Total", "December Total", "February Total", _
        "January Total", "January Total Total", "November Total", "October Total", _
        "October Total Total", "San Francisco Total"), Operator:=xlFilterValues
    Rows("16:29").Select
    Selection.ClearContents
End Sub

Хитрость заключается в том, чтобы заменить этот массив значений одним значением, использующим подстановочные знаки, то есть "*Total*". Сочетая это с вашим LastRow и другими переменными, я получаю:

Sub DeleteTotals()
Dim LastRow As Long
Dim r As Excel.Range

With ActiveSheet
    LastRow = .Range("B" & .Rows.Count).End(xlUp).Row
    Set r = .Range(Cells(4, "B"), Cells(LastRow, "B"))
End With
With r
    .AutoFilter Field:=1, Criteria1:="*Total*", Operator:=xlFilterValues
    .SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
End Sub

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

person Doug Glancy    schedule 19.03.2014
comment
АА, вижу. Это имеет смысл и, основываясь на некоторых других темах, с которыми я столкнулся, явно является мощным способом. Вчера мне не хватало понимания синтаксиса, чтобы реализовать его самостоятельно, пока вы не продемонстрировали это здесь. Я обязательно попробую. Большое спасибо за продолжение. - person Ephs05msm; 19.03.2014

Рассмотреть возможность:

Sub marine()
    Dim r As Range, rDelete As Range
    Set rDelete = Nothing
    LastRow = 100
    Set r = Range(Cells(4, "B"), Cells(LastRow, "B"))
    For Each rcell In r
        v = CStr(rcell.Value)
        If InStr(1, v, "Total") > 0 Then
            If rDelete Is Nothing Then
                Set rDelete = r
            Else
                Set rDelete = Union(r, rDelete)
            End If
        End If
    Next rcell

    If rDelete Is Nothing Then
    Else
        rDelete.EntireRow.Delete
    End If
End Sub

Используйте свой собственный код для вычисления LastRow

РЕДАКТИРОВАНИЕ №1:

Вот исправленная версия:

Sub marine()
    Dim r As Range, rDelete As Range
    Set rDelete = Nothing
    LastRow = 100
    Set r = Range(Cells(4, "B"), Cells(LastRow, "B"))
    For Each rcell In r
        v = CStr(rcell.Value)
        If InStr(1, v, "Total") > 0 Then
            If rDelete Is Nothing Then
                Set rDelete = rcell
            Else
                Set rDelete = Union(rcell, rDelete)
            End If
        End If
    Next rcell

    If rDelete Is Nothing Then
    Else
        rDelete.EntireRow.Delete
    End If
End Sub
person Gary's Student    schedule 18.03.2014
comment
Большое спасибо. В результате этот код удалил все строки, кроме первой. Возможно, я допустил ошибку при переводе вашего кода — я сохранил объектные переменные r, rcell и rdelete, поскольку ваш код ссылается на все три. Когда я запрашиваю непосредственное окно print rdelete.address непосредственно перед запуском метода entirerow.delete, оно возвращает $B$4:$B$1535 (в данном случае 1535=Lastrow). Спасибо еще раз. - person Ephs05msm; 18.03.2014
comment
Теперь работает отлично. Я собираюсь изучить подход здесь. Большое спасибо! - person Ephs05msm; 18.03.2014