简体   繁体   English

清除数组中行的内容-具有3个条件

[英]Clear the rows' content in the array - with 3 conditions

Some time ago I wanted to create a code that will clear the content of the rows in specific ranges of my sheet but only under a condition if the ID in the first column of my ranges matches the defined name with the first characters. 前段时间,我想创建一个代码来清除工作表特定范围内行的内容,但前提是条件是,范围的第一列中的ID与定义的名称与第一个字符相匹配。 I have got an excellent support from QHarr who made the code work. 我使QHarr得到了出色的支持,他使代码正常工作。

However, now, I wanted to extend the code for a few more conditions ie have 3 IDs (Defined names) to which the rows should be matched and then cleared. 但是,现在,我想将代码扩展到更多条件,即具有3个ID(定义的名称),行应与之匹配然后清除。 The current code works for 1 ID (Defined name) and after many trials I cannot make it work by extending the condition to 3 IDs (Defined names) 当前代码适用于1个ID(定义的名称),经过多次试验,我无法通过将条件扩展为3个ID(定义的名称)来使其工作

Here is how the case looks before running the code: 这是运行代码之前的情况: 在此处输入图片说明

This is the desired outcome => the rows in the array where 3 IDs matches to defined name - clear in the range: 这是所需的结果=>数组中3个ID与定义的名称匹配的行-在范围内清除:

在此处输入图片说明

Below is the code that works great for 1 ID: 以下是适用于1个ID的代码:

Option Explicit
Public Sub ClearCells()

    Const COLUMN_START1 As Long = 2
    Const COLUMN_END1 As Long = 5
    Const COLUMN_START2 As Long = 7
    Const COLUMN_END2 As Long = 10
    Const COLUMN_START3 As Long = 12
    Const COLUMN_END3 As Long = 15
    Const START_ROW As Long = 8
    Const L_MY_DEFINED_NAME As String = "ID"

    Dim loopRanges()

    loopRanges = Array(COLUMN_START1, COLUMN_END1, COLUMN_START2, COLUMN_END2, COLUMN_START3, COLUMN_END3)

    Dim targetSheet As Worksheet, index As Long, unionRng As Range
    Dim id As Long                               'Or , ID As String?

    Set targetSheet = ThisWorkbook.Sheets("Sheet1")
    id = ThisWorkbook.Names(L_MY_DEFINED_NAME).RefersToRange.Value

    Application.ScreenUpdating = False

    With targetSheet

        For index = LBound(loopRanges) To UBound(loopRanges) Step 2

            Dim lngLastRow As Long, ClearRange As Range, rng As Range

            lngLastRow = .Cells(.Rows.Count, loopRanges(index)).End(xlUp).Row '
            If lngLastRow < START_ROW Then lngLastRow = START_ROW

            Set ClearRange = .Range(.Cells(START_ROW, loopRanges(index)), .Cells(lngLastRow, loopRanges(index + 1)))

            For Each rng In ClearRange.Columns(1).Cells
                If Not IsEmpty(rng) Then
                    If Left$(rng.Value, Len(id)) = id Then '<== match found
                        If Not unionRng Is Nothing Then
                            Set unionRng = Union(unionRng, rng.Resize(1, ClearRange.Columns.Count)) '<== gather all matches into a union range

                        Else
                            Set unionRng = rng.Resize(1, ClearRange.Columns.Count)
                        End If
                    End If
                End If
            Next rng
        Next index
    End With

    If Not unionRng Is Nothing Then unionRng.ClearContents '<== or after Then: 'Debug.Print unionRng.Address' to check what is cleared
    Application.ScreenUpdating = True
MsgBox "Done", vbInformation
End Sub

I was trying to extend it to 3 ids (defined names) on multiple ways and none of them works eg In the statement 'If Left$(rng.Value, Len(id)) = id Then' , I was adding And, Or for id2 and id3 (after declaring them in the same way as ID) - however, the code does not read them. 我试图以多种方式将其扩展为3个id(定义的名称),但它们都不起作用,例如在语句'If Left $(rng.Value,Len(id))= id then'中,我添加了And或对于id2和id3(以与ID相同的方式声明它们之后)-但是,代码不会读取它们。 I had also tried to add the paragraphs of the condition for id below as for id2 and id3 - but in the outcome, the whole content of the sheet is cleared. 我也曾尝试在下面为id2和id3添加id条件的段落-但结果是,工作表的全部内容都被清除了。 Does someone know the trick to extend it? 有人知道扩展它的技巧吗?

The advantage of the solutions below is that you can continue using your approach of start and end columns to extend for more ranges. 以下解决方案的优势在于,您可以继续使用起始列和结束列的方法扩展更多范围。

If you know that they will match on length you can do: 如果您知道它们的长度匹配,则可以执行以下操作:

Option Explicit
Public Sub ClearCells()

    Const COLUMN_START1 As Long = 2
    Const COLUMN_END1 As Long = 5
    Const COLUMN_START2 As Long = 7
    Const COLUMN_END2 As Long = 10
    Const COLUMN_START3 As Long = 12
    Const COLUMN_END3 As Long = 15
    Const START_ROW As Long = 8
    'Const L_MY_DEFINED_NAME As String = "ID"

    Dim loopRanges()

    loopRanges = Array(COLUMN_START1, COLUMN_END1, COLUMN_START2, COLUMN_END2, COLUMN_START3, COLUMN_END3)

    Dim targetSheet As Worksheet, index As Long, unionRng As Range
    Dim id As Long                               'Or , ID As String?

    Set targetSheet = ThisWorkbook.Sheets("Sheet1")
    'id = ThisWorkbook.Names(L_MY_DEFINED_NAME).RefersToRange.Value

    Application.ScreenUpdating = False

    With targetSheet

        For index = LBound(loopRanges) To UBound(loopRanges) Step 2

            Dim lngLastRow As Long, ClearRange As Range, rng As Range

            lngLastRow = .Cells(.Rows.Count, loopRanges(index)).End(xlUp).Row '
            If lngLastRow < START_ROW Then lngLastRow = START_ROW

            Set ClearRange = .Range(.Cells(START_ROW, loopRanges(index)), .Cells(lngLastRow, loopRanges(index + 1)))

            For Each rng In ClearRange.Columns(1).Cells
                If Not IsEmpty(rng) Then
                    If Not IsError(Application.Match(rng.Value, targetSheet.Range("B3:B5"), 0)) Then 'Left$(rng.Value, Len(id)) = id Then '<== match found
                        If Not unionRng Is Nothing Then
                            Set unionRng = Union(unionRng, rng.Resize(1, ClearRange.Columns.Count)) '<== gather all matches into a union range

                        Else
                            Set unionRng = rng.Resize(1, ClearRange.Columns.Count)
                        End If
                    End If
                End If
            Next rng
        Next index
    End With

    If Not unionRng Is Nothing Then unionRng.ClearContents '<== or after Then: 'Debug.Print unionRng.Address' to check what is cleared
    Application.ScreenUpdating = True
MsgBox "Done", vbInformation
End Sub

Or: 要么:

Option Explicit
Public Sub ClearCells()

    Const COLUMN_START1 As Long = 2
    Const COLUMN_END1 As Long = 5
    Const COLUMN_START2 As Long = 7
    Const COLUMN_END2 As Long = 10
    Const COLUMN_START3 As Long = 12
    Const COLUMN_END3 As Long = 15
    Const START_ROW As Long = 8
    'Const L_MY_DEFINED_NAME As String = "ID"

    Dim loopRanges()

    loopRanges = Array(COLUMN_START1, COLUMN_END1, COLUMN_START2, COLUMN_END2, COLUMN_START3, COLUMN_END3)

    Dim targetSheet As Worksheet, index As Long, unionRng As Range
    Dim id As Long                               'Or , ID As String?

    Set targetSheet = ThisWorkbook.Sheets("Sheet1")
    'id = ThisWorkbook.Names(L_MY_DEFINED_NAME).RefersToRange.Value

    Dim ids()
    ids = targetSheet.Range("B3:B5").Value

    Application.ScreenUpdating = False

    With targetSheet

        For index = LBound(loopRanges) To UBound(loopRanges) Step 2

            Dim lngLastRow As Long, ClearRange As Range, rng As Range

            lngLastRow = .Cells(.Rows.Count, loopRanges(index)).End(xlUp).Row '
            If lngLastRow < START_ROW Then lngLastRow = START_ROW

            Set ClearRange = .Range(.Cells(START_ROW, loopRanges(index)), .Cells(lngLastRow, loopRanges(index + 1)))

            For Each rng In ClearRange.Columns(1).Cells
                If Not IsEmpty(rng) Then
                    If Not IsError(Application.Match(rng.Value, Application.WorksheetFunction.index(ids, 0, 1), 0)) Then 'Left$(rng.Value, Len(id)) = id Then '<== match found
                        If Not unionRng Is Nothing Then
                            Set unionRng = Union(unionRng, rng.Resize(1, ClearRange.Columns.Count)) '<== gather all matches into a union range

                        Else
                            Set unionRng = rng.Resize(1, ClearRange.Columns.Count)
                        End If
                    End If
                End If
            Next rng
        Next index
    End With

    If Not unionRng Is Nothing Then unionRng.ClearContents '<== or after Then: 'Debug.Print unionRng.Address' to check what is cleared
    Application.ScreenUpdating = True
MsgBox "Done", vbInformation
End Sub

In the first answer you simply lookup the current cell value against the range holding the IDs with 在第一个答案中,您只需根据保存ID的范围查找当前单元格值即可

If Not IsError(Application.Match(rng.Value, targetSheet.Range("B3:B5"), 0)) 

If there is a match then you add it to the items for later clearance. 如果有匹配项,则将其添加到项目中以供以后清除。

In the second answer you put the IDs into an array and when looping check if the current cell value is in the array with: 在第二个答案中,将ID放入数组中,并在循环时使用以下命令检查当前单元格值是否在数组中:

If Not IsError(Application.Match(rng.Value, Application.WorksheetFunction.index(ids, 0, 1), 0)) 

Edit: 编辑:

If you don't know that they will match on length you can extend your original code to loop all the IDs like this: 如果您不知道它们的长度是否匹配,可以扩展原始代码以循环所有ID,如下所示:

Option Explicit

Public Sub ClearCells()

    Const COLUMN_START1 As Long = 2
    Const COLUMN_END1 As Long = 5
    Const COLUMN_START2 As Long = 7
    Const COLUMN_END2 As Long = 10
    Const COLUMN_START3 As Long = 12
    Const COLUMN_END3 As Long = 15
    Const START_ROW As Long = 8
    'Const L_MY_DEFINED_NAME As String = "ID"

    Dim loopRanges()

    loopRanges = Array(COLUMN_START1, COLUMN_END1, COLUMN_START2, COLUMN_END2, COLUMN_START3, COLUMN_END3)

    Dim targetSheet As Worksheet, index As Long, unionRng As Range
    Dim id As Long                               'Or , ID As String?

    Set targetSheet = ThisWorkbook.Sheets("Sheet1")
    'id = ThisWorkbook.Names(L_MY_DEFINED_NAME).RefersToRange.Value

    Dim ids(), i As Long
    ids = targetSheet.Range("B3:B5").Value

    Application.ScreenUpdating = False

    With targetSheet

        For i = LBound(ids, 1) To UBound(ids, 1)

        For index = LBound(loopRanges) To UBound(loopRanges) Step 2

            Dim lngLastRow As Long, ClearRange As Range, rng As Range

            lngLastRow = .Cells(.Rows.Count, loopRanges(index)).End(xlUp).Row '
            If lngLastRow < START_ROW Then lngLastRow = START_ROW

            Set ClearRange = .Range(.Cells(START_ROW, loopRanges(index)), .Cells(lngLastRow, loopRanges(index + 1)))

            For Each rng In ClearRange.Columns(1).Cells
                If Not IsEmpty(rng) Then
                    If Left$(rng.Value, Len(ids(i, 1))) = ids(i, 1) Then '<== match found
                        If Not unionRng Is Nothing Then
                            Set unionRng = Union(unionRng, rng.Resize(1, ClearRange.Columns.Count)) '<== gather all matches into a union range

                        Else
                            Set unionRng = rng.Resize(1, ClearRange.Columns.Count)
                        End If
                    End If
                End If
            Next rng
        Next index

        Next i

    End With

    If Not unionRng Is Nothing Then unionRng.ClearContents '<== or after Then: 'Debug.Print unionRng.Address' to check what is cleared
    Application.ScreenUpdating = True
MsgBox "Done", vbInformation
End Sub

a "quick & dirty" code: “快速且肮脏的”代码:

Sub main()
    Dim iCol As Long
    Dim filters As Variant, filter As Variant
    Dim cell As Range

    filters = Array("1234", "432", "5544") '<- list your named ranges values

    With ThisWorkbook.Sheets("Sheet1")
        For iCol = 2 To 12 Step 5
            For Each cell In .Range(.Cells(8, iCol), .Cells(.Rows.count, iCol).End(xlUp))
                For Each filter In filters
                    If InStr(cell.Text, filter) > 0 Then
                        cell.Resize(, 4).ClearContents
                        Exit For
                    End If
                Next
            Next
        Next
    End With
End Sub

a less dirty code, limiting the iteration to the actual number of matches: 不太脏的代码,将迭代限制为实际的匹配数:

Sub main2()
    Dim iCol As Long
    Dim filters As Variant, filter As Variant
    Dim f As Range

    filters = Array("1234", "432", "5544")

    With ThisWorkbook.Sheets("Sheet001")
        For iCol = 2 To 12 Step 5
            With .Range(.Cells(8, iCol), .Cells(.Rows.count, iCol).End(xlUp))
                For Each filter In filters
                    Set f = .Find(what:=filter, LookIn:=xlValues, lookat:=xlPart)
                    If Not f Is Nothing Then
                        Do
                            f.Resize(, 4).ClearContents
                            Set f = .FindNext(f)
                        Loop While Not f Is Nothing
                    End If
                Next
            End With
        Next
    End With
End Sub

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM