如何根据单元格内容构建非连续的行范围?

时间:2013-07-20 10:20:41

标签: excel vba excel-vba excel-2011

我刚刚开始使用VBA for Excel。近十年前我在大学里使用过VB和Java,并且当时很有能力,但我基本上已经开始了。 (嗯,不喜欢骑自行车。)

我正在尝试理解构建范围的方法,该范围不仅仅声明为A1:J34或其他。我的谷歌搜索受到挑战,因为当搜索“范围”和表示我所寻求的内容的术语时,我得到的雪崩远比我需要的更高级,主要是甚至没有解决我需要的基本摘要信息的命中。 / p>

所以,这是它的基础知识: Mac上的Excel 2011。 工作表的数据从A到M,低至1309。 它是标题行的重复模式,后跟数据行。啊。似乎创建工作表的人更多地考虑从工作表打印而不是数据组织。我需要清理它,还有3个像它一样用在数据透视表中,而且在这个愚蠢的重复布局中它是无用的。

标题行如下: 姓氏,名字,然后10个日期单元格。 标题下的数据行当然是名称,然后是1或0表示出席。 每个标题下的名称从20到30个。然后它重复。日期每隔几套就会改变一次,从最后一组停止的地方开始。

我现在需要做的事情: 我试图通过添加以特定值开头的所有行(在A列中)将范围组合成范围变量。在我的情况下,值是字符串“姓氏”,所以我可以使用范围变量保存所有以“姓氏”开头的行中的所有单元格。然后,这将捕获需要采用日期格式的所有单元格。 (我这样做,所以我可以确保日期标题都是实际的日期格式 - 因为它们现在都不是日期格式,许多只是'一般'单元格。)

我的问题:

  1. 当告诉范围对象它的范围是什么时,如何提供单元格/行/列,这些单元格/行/列不仅是由编写代码的人输入的开始和结束单元格定义的块,而是基于行标准?例如:根据A中“名字”的存在,创建一个从第A列到第I列包含行1,34,70,93和128的范围。
  2. 最常用的方法是什么?
  3. 哪一种最适合我的需要以及为什么?

2 个答案:

答案 0 :(得分:1)

这是一个工作示例,演示了如何查找“姓氏”行,构建包含所有这些行的范围对象,然后遍历该对象以搜索非日期值。通过将数据范围读入变量数组,然后在数组中搜索姓氏行和这些行中的“错误日期”,可以极大地加速代码。如果要检查的行数非常多,则尤其如此。

Sub DisjointRng()

    Dim checkCol As String, checkPattern As String
    Dim dateCols()
    Dim lastCell As Range, usedRng As Range, checkRng As Range
    Dim cell As Variant
    Dim usedRow As Range, resultRng As Range, rngArea As Range
    Dim i As Long, j As Long

    checkCol = "A"             'column to check for "Last Name"
    checkPattern = "Last*"
    dateCols = Array(3, 5)     'columns to check for date formatting

    With Worksheets("Sheet1")
        'find the bottom right corner of data range; we determine the used range
            'ourselves since the built-in UsedRange is sometimes out-of-synch
        Set lastCell = .Cells(.Cells.Find(What:="*", SearchOrder:=xlRows, _
            SearchDirection:=xlPrevious, LookIn:=xlFormulas).Row, _
            .Cells.Find(What:="*", SearchOrder:=xlByColumns, _
            SearchDirection:=xlPrevious, LookIn:=xlFormulas).Column)
        Set usedRng = .Range("A1:" & lastCell.Address)
        'the column of values in which to look for "Last Name"
        Set checkRng = .Range(checkCol & "1:" & checkCol & usedRng.Rows.Count)
    End With
    'step down the column of values to check for last name & add
        'add found rows to range object
    For Each cell In checkRng
        If cell.Value Like checkPattern Then
           'create a range object for the row
            Set usedRow = Intersect(cell.EntireRow, usedRng)
            If resultRng Is Nothing Then
                'set the first row with "Last Name"
                Set resultRng = usedRow
            Else
                'add each additional found row to the result range object
                Set resultRng = Union(resultRng, usedRow)
            End If
        End If
    Next cell
    For Each rngArea In resultRng.Areas
        'if found rows are continguous, Excel consolidates them
            'into single area, so need to loop through each of the rows in area
        For i = 1 To rngArea.Rows.Count
            For j = LBound(dateCols) To UBound(dateCols)
                If Not IsDate(rngArea.Cells(i, dateCols(j))) Then
                    'do something
                End If
            Next j
        Next i
    Next rngArea
End Sub

答案 1 :(得分:0)

您可以使用Union运算符,例如

Dim r As Range

Set r = Range("A1, A3, A10:A12")

或者

Set r = Union(Range("A1"), Range("A3"), Range("A10:A12"))

你可以像这样迭代这个范围

Dim cl as Range
For Each cl in r.Cells
    ' code cell cl
Next

或者

Dim ar as Range
For each ar in r.Areas
    ' code using contiguous range ar
    For each cl in ar.Cells
        ' code using cell cl
    Next
Next