Excel VBA:查找第N个字段名称的列号

时间:2018-12-15 22:11:12

标签: excel vba

我有一个函数,可以在其中指定所需的字段和标题行号,然后返回该列。例如。 =findField("Region",1)将返回包含标题“ Region”的列号。在我遇到标题行中包含重复名称的报告之前,此方法一直有效。例如。而不是第一个和姓氏,在两个字段中都将使用“名称”,因此我需要像第二个事件中的=findField("Name",1,2)中那样指定我想要的事件。我想出了一个解决方案,但有2个问题。首先是,如果该字段在第一列中,它将无法正常工作。例如。如果列A和列B具有“名称”,那么=findField("Name",1,1)将返回第二个字段而不是第一个字段,而=findField("Name",1,2)将环绕并返回第一个字段,这不是我想要的。第二个问题是,它包裹了我不希望完全不做的地方。我想到的是:

Function findField2(fieldName As String, Optional rowStart As Long = 0, Optional occurrence As Long = 1)
    Dim Found As Range, lastRow As Long, count As Integer, myCol As Long

    If rowStart = 0 Then rowStart = getHeaderRow()
    myCol = 1

    For count = 1 To occurrence
        Set Found = Rows(rowStart).Find(what:=fieldName, LookIn:=xlValues, lookat:=xlWhole, After:=Cells(rowStart, myCol))

        If Found Is Nothing Then
            MsgBox "Error: Can't find '" & fieldName & "' in row " & rowStart
            Exit Function
        Else
            myCol = Found.Column
        End If
    Next count

    lastRow = Cells(Rows.count, Found.Column).End(xlUp).Row
    findField2 = Found.Column

要允许该字段位于A列中,我需要做什么?为myCol输入0无效。最初的查找功能基于https://www.mrexcel.com/forum/excel-questions/629346-vba-finding-text-row-1-return-column.html,我正在对其进行调整以满足自己的需求。

谢谢, 本

4 个答案:

答案 0 :(得分:1)

有些不使用Find()的东西仍然可以满足您的目标:

Function findField2(fieldName As String, Optional rowStart As Long = 0, _
                                           Optional occurrence As Long = 1)
    Dim a, rw As Range, m

    If rowStart = 0 Then rowStart = getHeaderRow()

    With ActiveSheet 'might be better to pass the sheet as a parameter
        Set rw = Application.Intersect(.Rows(rowStart), .UsedRange)
        a = .Evaluate("=IF(" & rw.Address & "=""" & fieldName & _
                            """,COLUMN(" & rw.Address & "),FALSE)")
    End With

    m = Application.Small(a, occurrence) 'find the n'th match (will return an error if none)

    If IsError(m) Then MsgBox "No occurrence #" & occurrence & " of '" & _
                              fieldName & "' on row# " & rowStart, vbExclamation

    findField2 = IIf(IsError(m), 0, m)
End Function

Sub Tester()
    Debug.Print findField2("A", 5, 40)
End Sub

答案 1 :(得分:0)

行中列专项功能。环绕问题

此处没有对象引用,即,所有内容都引用了ActiveSheet中的ActiveWorkbook

查找(之后)

通过默认查找方法从下一个单元格开始搜索(6. SearchDirection xlNext或{{1} })中提供的After参数(2. After )的单元格范围参数,例如,如果您按行使用单元格1(5. SearchOrder { 1}}或A1),搜索将从xlByRows开始,一直进行到最后一列,然后回绕并最后继续1。因此,必须使用该行的最后单元格以第一个单元格B1开始搜索。

环绕

仅当出现次数大于1时,才用A1语句解决环绕问题。如果未发现任何出现,则返回A1
找到的单元格(If)的列号将传递到变量(0),并且每次出现该值时,都将相互检查它们。现在,如果变量等于列号,则函数返回intCol,表示找到了值,但未找到指定的出现次数。

intWrap

答案 2 :(得分:0)

感谢您的回复。我正在学习有用的技术,这对您有很大的帮助。我实际上修复了基于@TimWilliams的第一个问题,将myCol设置为最后一列,因此它在第一列开始查找,并根据下面的内容添加了环绕检查。我还更改了msgBox,以根据每个@ VBasic2008返回一个值。

Function findField2(fieldName As String, Optional rowStart As Long = 0, Optional occurrence As Long = 1)
    Dim Found As Range, lastRow As Long, count As Integer, myCol As Long

    If rowStart = 0 Then rowStart = getHeaderRow()
    myCol = 16384

    For count = 1 To occurrence
        Set Found = Rows(rowStart).Find(what:=fieldName, LookIn:=xlValues, lookat:=xlWhole, After:=Cells(rowStart, myCol))

        ' Check if nothing found or for wrap around and Nth occurrence not found
        If Found Is Nothing Or count > 1 And Found.Column <= myCol Then
            findField2 = 0
            Exit Function
        Else
            myCol = Found.Column
        End If
    Next count


    lastRow = Cells(Rows.count, Found.Column).End(xlUp).Row
    findField2 = Found.Column
End Function

这是上面的findField函数中提到的getHeaderRow函数:

Function getHeaderRow() As Long
    Dim i As Long, lastCol As Long, lastRow As Long
    lastCol = Cells.Find("*", [a1], , , xlByColumns, xlPrevious).Column
    lastRow = Cells.Find("*", [a1], , , xlByRows, xlPrevious).Row
    i = 1

    Do While Cells(i, lastCol).Value = ""
        i = i + 1
        If i > lastRow Then
            i = 0
            Exit Do
        End If
    Loop

    getHeaderRow = i
End Function

答案 3 :(得分:0)

此版本使用FindNext搜索第一个之后的事件。
它将搜索代码所在的工作簿的Sheet1ThisWorkbook):

Sub Test()

    Dim MyCell As Range

    'Second occurrence default row.
    Set MyCell = FindField("Date", Occurrence:=3)

    If Not MyCell Is Nothing Then
        MsgBox "Found in cell " & MyCell.Address & "." & vbCr & _
            "Row: " & MyCell.Row & vbCr & "Column: " & MyCell.Column & vbCr & _
            "Sheet: '" & MyCell.Parent.Name & "'" & vbCr & _
            "Workbook: '" & MyCell.Parent.Parent.Name & "'", vbOKOnly + vbInformation
    Else
        MsgBox "Value not found."
    End If

End Sub

Public Function FindField(FieldName As String, Optional RowStart As Long = 0, _
    Optional Occurrence As Long = 1) As Range

    Dim rFound As Range
    Dim x As Long
    Dim sFirstAdd As String

    If RowStart = 0 Then RowStart = 1
    x = 1

    With ThisWorkbook.Worksheets("Sheet1").Rows(RowStart)
        Set rFound = .Find( _
            What:=FieldName, _
            LookIn:=xlValues, _
            LookAt:=xlWhole, _
            After:=.Cells(RowStart, .Columns.Count))

        If Not rFound Is Nothing Then
            Set FindField = rFound
            If Occurrence <> 1 Then
                sFirstAdd = rFound.Address
                Do
                    Set rFound = .FindNext(rFound)
                    x = x + 1

                Loop While x <> Occurrence And rFound.Address <> sFirstAdd
                If rFound.Address = sFirstAdd Then
                    Set FindField = Nothing
                End If
            End If
        End If
    End With

End Function