分享

[VBA]关于查找方法(Find方法)的应用

 庋藏天下 2013-06-29

[VBA]关于查找方法(Find方法)的应用  fanjy 发表于 2006-9-28 20:14:00 

关于查找方法(Find方法)的应用()

--------------------------------------------------------------------------------

Excel中,选择菜单“编辑”——“查找(F)…”命令或者按“Ctrl+F”组合键,将弹出如下图01所示的“查找和替换”对话框。在“查找”选项卡中,输入需要查找的内容并设置相关选项后进行查找,Excel会将活动单元格定位在查找到的相应单元格中。如果未发现查找的内容,Excel会弹出“Excel找不到正在搜索的数据”的消息框。

 

01:“查找”对话框

Excel的这个功能对查找指定的数据非常有用,特别是在含有大量数据的工作表中搜索数据时,更能体现出该功能的快速和便捷。同样,在ExcelVBA中使用与该功能对应的Find方法,提供了一种在单元格区域查找特定数据的简单方式,并且比用传统的循环方法进行查找的速度更快。

--------------------------------------------------------------------------------

1. Find方法的作用

Find方法将在指定的单元格区域中查找包含参数指定数据的单元格,若找到符合条件的数据,则返回包含该数据的单元格;若未发现相匹配的数据,则返回Nothing。该方法返回一个Range对象,在使用该方法时,不影响选定区域或活动单元格。

--------------------------------------------------------------------------------

2. Find方法的语法

[语法]

<单元格区域>.Find (What[After][LookIn][LookAt][SearchOrder][SearchDirection][MatchCase][MatchByte][SearchFormat])

[参数说明]

(1)<单元格区域>,必须指定,返回一个Range对象。

(2)参数What,必需指定。代表所要查找的数据,可以为字符串、整数或者其它任何数据类型的数据。对应于“查找与替换”对话框中,“查找内容”文本框中的内容。

(3)参数After,可选。指定开始查找的位置,即从该位置所在的单元格之后向后或之前向前开始查找(也就是说,开始时不查找该位置所在的单元格,直到Find方法绕回到该单元格时,才对其内容进行查找)。所指定的位置必须是单元格区域中的单个单元格,如果未指定本参数,则将从单元格区域的左上角的单元格之后开始进行查找。

(4)参数LookIn,可选。指定查找的范围类型,可以为以下常量之一:xlValuesxlFormulas或者xlComments,默认值为xlFormulas。对应于“查找与替换”对话框中,“查找范围”下拉框中的选项。

(5)参数LookAt,可选。可以为以下常量之一:XlWhole或者xlPart,用来指定所查找的数据是与单元格内容完全匹配还是部分匹配,默认值为xlPart。对应于“查找与替换”对话框中,“单元格匹配”复选框。

(6)参数SearchOrder,可选。用来确定如何在单元格区域中进行查找,是以行的方式(xlByRows)查找,还是以列的方式(xlByColumns)查找,默认值为xlByRows。对应于“查找与替换”对话框中,“搜索”下拉框中的选项。

(7)参数SearchDirection,可选。用来确定查找的方向,即是向前查找(XlPrevious)还是向后查找(xlNext),默认的是向后查找。

(8)参数MatchCase,可选。若该参数值为True,则在查找时区分大小写。默认值为False。对应于“查找与替换”对话框中,“区分大小写”复选框。

(9)参数MatchByter,可选。即是否区分全角或半角,在选择或安装了双字节语言时使用。若该参数为True,则双字节字符仅与双字节字符相匹配;若该参数为False,则双字节字符可匹配与其相同的单字节字符。对应于“查找与替换”对话框中,“区分全角/半角”复选框。

(10)参数SearchFormat,可选,指定一个确切类型的查找格式。对应于“查找与替换”对话框中,“格式”按钮。当设置带有相应格式的查找时,该参数值为True

(11)在每次使用Find方法后,参数LookInLookAtSearchOrderMatchByte的设置将保存。如果下次使用本方法时,不改变或指定这些参数的值,那么该方法将使用保存的值。

VBA中设置的这些参数将更改“查找与替换”对话框中的设置;同理,更改“查找与替换”对话框中的设置,也将同时更改已保存的值。也就是说,在编写好一段代码后,若在代码中未指定上述参数,可能在初期运行时能满足要求,但若用户在“查找与替换”对话框中更改了这些参数,它们将同时反映到程序代码中,当再次运行代码时,运行结果可能会产生差异或错误。若要避免这个问题,在每次使用时建议明确的设置这些参数。

3. Find方法使用示例

3.1 本示例在活动工作表中查找what变量所代表的值的单元格,并删除该单元格所在的列。

'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Sub Find_Error()

  Dim rng As Range

  Dim what As String

  what = "Error"

  Do

    Set rng = ActiveSheet.UsedRange.Find(what)

    If rng Is Nothing Then

      Exit Do

    Else

       Columns(rng.Column).Delete

    End If

  Loop

End Sub

'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

3.2 带格式的查找

本示例在当前工作表单元格中查找字体为"Arial Unicode MS"且颜色为红色的单元格。其中,Application.FindFormat对象允许指定所需要查找的格式,此时Find方法的参数SearchFormat应设置为True

'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Sub FindWithFormat()

  With Application.FindFormat.Font

        .Name = "Arial Unicode MS"

        .ColorIndex = 3

  End With

  Cells.Find(what:="", SearchFormat:=True).Activate

End Sub

'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

[小结] 在使用Find方法找到符合条件的数据后,就可以对其进行相应的操作了。您可以:

(1)对该数据所在的单元格进行操作;

(2)对该数据所在单元格的行或列进行操作;

(3)对该数据所在的单元格区域进行操作。

 

--------------------------------------------------------------------------------

4. Find方法相联系的方法

可以使用FindNext方法和FindPrevious方法进行重复查找。在使用这两个方法之前,必须用Find方法指定所需要查找的数据内容。

4.1 FindNext方法

FindNext方法对应于“查找与替换”对话框中的“查找下一个”按钮。可以使用该方法继续执行查找,查找下一个与Find方法中所指定条件的数据相匹配的单元格,返回代表该单元格的Range对象。在使用该方法时,不影响选定区域或活动单元格。

4.1.1 语法

<单元格区域>.FindNext(After)

4.1.2 参数说明

参数After,可选。代表所指定的单元格,将从该单元格之后开始进行查找。开始时不查找该位置所在的单元格,直到FindNext方法绕回到该单元格时,才对其内容进行查找。所指定的位置必须是单元格区域中的单个单元格,如果未指定本参数,则将从单元格区域的左上角的单元格之后开始进行查找。

当查找到指定查找区域的末尾时,本方法将环绕至区域的开始继续查找。发生环绕后,为停止查找,可保存第一次找到的单元格地址,然后测试下一个查找到的单元格地址是否与其相同,作为判断查找退出的条件,以避免出现死循环。当然,如果在查找的过程中,将查找到的单元格数据进行了改变,也可不作此判断,如下例所示。

4.1.3 VBA帮助系统上的一点疑问探讨

VBA帮助系统中,介绍Find方法和FindNext方法所使用的示例好像有点问题:当在Excel中运行时,虽然运行结果正确,但是在运行到最后时,会报错误:运行时错误’91:对象变量或With块变量未设置。究其原因,可能是对象变量c的问题,因为当进行查找并将相应的值全部改变后,最后变量c的值为Nothing。将其稍作改动后,运行通过。

原示例代码如下:(大家也可参见VBA帮助系统Find方法或FindNext方法帮助主题)

本示例在单元格区域A1:A500中查找值为2的单元格,并将这些单元格的值变为5

With Worksheets(1).Range("a1:a500")

  Set c = .Find(2, lookin:=xlValues)

  If Not c Is Nothing Then

    firstAddress = c.Address

    Do

      c.Value = 5

      Set c = .FindNext(c)

    Loop While Not c Is Nothing And c.Address <> firstAddress

  End If

End With

经修改后的示例代码如下,即在原代码中加了一句错误处理语句On Error Resume Next,忽略所发生的错误。

Sub test1()

  Dim c As Range, firstAddress As String

  On Error Resume Next

  With Worksheets(1).Range("a1:a15")

    Set c = .Find(2, LookIn:=xlValues)

    If Not c Is Nothing Then

      firstAddress = c.Address

      Do

        c.Value = 5

        Set c = .FindNext(c)

      Loop While Not c Is Nothing And c.Address <> firstAddress

    End If

  End With

End Sub

或者,将代码作如下修改,即去掉原代码中最后一个判断循环的条件c.Address <> firstAddress,因为本程序的功能是在指定区域查找值为2的单元格并替换为数值5,当程序在指定区域查找不到数值2时就会退出循环,不涉及到重复循环的问题。

Sub test2()

  Dim c As Range, firstAddress As String

  With Worksheets(1).Range("a1:a15")

    Set c = .Find(2, LookIn:=xlValues)

    If Not c Is Nothing Then

      firstAddress = c.Address

      Do

        c.Value = 5

        Set c = .FindNext(c)

      Loop While Not c Is Nothing

    End If

  End With

End Sub

您也可以试试该程序,看看我的理解是否正确,或者还有什么其它的解决办法。

4.2 FindPrevious方法

可以使用该方法继续执行Find方法所进行的查找,查找前一个与Find方法中所指定条件的数据相匹配的单元格,返回代表该单元格的Range对象。在使用该方法时,不影响选定区域或活动单元格。

4.2.1 语法

<单元格区域>.FindPrevious(After)

4.2.2 参数说明

参数After,可选。代表所指定的单元格,将从该单元格之前开始进行查找。开始时不查找该位置所在的单元格,直到FindPrevious方法绕回到该单元格时,才对其内容进行查找。所指定的位置必须是单元格区域中的单个单元格,如果未指定本参数,则将从单元格区域的左上角的单元格之前开始进行查找。

当查找到指定查找区域的起始位置时,本方法将环绕至区域的末尾继续查找。发生环绕后,为停止查找,可保存第一次找到的单元格地址,然后测试下一个查找到的单元格地址是否与其相同,作为判断查找退出的条件,以避免出现死循环。

4.2.3 示例

在工作表中输入如下图02所示的数据,至少保证在A列中有两个单元格输入了数据“excelhome”。

 02:测试的数据

VBE编辑器中输入下面的代码测试Find方法、FindNext方法、FindPrevious方法,体验各个方法所查找到的单元格位置。

'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Sub testFind()

  Dim findValue As Range

  Set findValue = Worksheets("Sheet1").Columns("A").Find(what:="excelhome")

  MsgBox "第一个数据发现在单元格:" & findValue.Address

  Set findValue = Worksheets("Sheet1").Columns("A").FindNext(After:=findValue)

  MsgBox "下一个数据发现在单元格:" & findValue.Address

  Set findValue = Worksheets("Sheet1").Columns("A").FindPrevious(After:=findValue)

  MsgBox "前一个数据发现在单元格" & findValue.Address

End Sub

'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

关于查找方法(Find方法)的应用()

--------------------------------------------------------------------------------

5. 综合示例

5.1 示例一:在当前工作表的单元格区域A1:A50中输入数据5和其它的一些数据,然后在VBE编辑器中输入下面的代码。运行后,程序将在单元格A1:A50区域中查找数值5所在的单元格,并在所找到的单元格中画一个蓝色的椭圆。

'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Sub FindSample1()

  Dim Cell As Range, FirstAddress As String

  With Worksheets(1).Range("A1:A50")

    Set Cell = .Find(5)

    If Not Cell Is Nothing Then

       FirstAddress = Cell.Address

       Do

         With Worksheets(1).Ovals.Add(Cell.Left, _

                                      Cell.Top, Cell.Width, _

                                      Cell.Height)

                                 .Interior.Pattern = xlNone

                                 .Border.ColorIndex = 5

         End With

         Set Cell = .FindNext(Cell)

         Loop Until Cell Is Nothing Or Cell.Address = FirstAddress

    End If

  End With

End Sub

'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

[参考] 参见《使VBA代码更快且更简洁的方法》一文中的“使用已有的VBA方法:Find方法”,体验使用传统的循环方法与使用该方法实现相同功能时,VBA代码速度的差异。

5.2 示例二:在一个列表中复制相关数据到另一个列表(Revised from Hansens Programming)

本程序的功能是,根据单元格I1中的值,在单元格区域A1:D11中的B列进行查找,每次找到相应的值,就将该单元格所在区域的行数据复制到以单元格G3(该单元格命名为found)开始的区域中。原数据如下图03所示。

   

03:原始数据

点击工作表中的“查找”按钮,运行后的结果如下图04所示。

   

04:运行后的结果

源程序代码清单及相关说明如下:

'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Option Explicit

Sub FindSample2()

  Dim ws As Worksheet

  Dim rgSearchIn As Range

  Dim rgFound As Range

  Dim sFirstFound As String

  Dim bContinue As Boolean

 

  ReSetFoundList '初始化要复制的列表区域

  Set ws = ThisWorkbook.Worksheets("sheet1")

  bContinue = True

  Set rgSearchIn = GetSearchRange(ws) '获取查找区域

 

  '设置查找参数

  Set rgFound = rgSearchIn.Find(what:=ws.Range("I1").Value, _

             LookIn:=xlValues, LookAt:=xlWhole)

 

  '获取第一个满足条件的单元格地址,作为结束循环的条件

  If Not rgFound Is Nothing Then sFirstFound = rgFound.Address

 

  Do Until rgFound Is Nothing Or Not bContinue

    CopyItem rgFound

    Set rgFound = rgSearchIn.FindNext(rgFound)

    '判断循环是否中止

    If rgFound.Address = sFirstFound Then bContinue = False

  Loop

 

  Set rgSearchIn = Nothing

  Set rgFound = Nothing

  Set ws = Nothing

End Sub

 

'获取查找区域,B列中的"部位"单元格区域

Private Function GetSearchRange(ws As Worksheet) As Range

  Dim lLastRow As Long

  lLastRow = ws.Cells(65536, 1).End(xlUp).Row

  Set GetSearchRange = ws.Range(ws.Cells(1, 2), ws.Cells(lLastRow, 2))

End Function

 

'复制查找到的数据到found区域

Private Sub CopyItem(rgItem As Range)

  Dim rgDestination As Range

  Dim rgEntireItem As Range

 

  '获取在查找区域中的整行数据

  Set rgEntireItem = rgItem.Offset(0, -1)

  Set rgEntireItem = rgEntireItem.Resize(1, 4)

 

  Set rgDestination = rgItem.Parent.Range("found")

  '定位要复制到的found区域的第一行

  If IsEmpty(rgDestination.Offset(1, 0)) Then

    Set rgDestination = rgDestination.Offset(1, 0)

  Else

    Set rgDestination = rgDestination.End(xlDown).Offset(1, 0)

  End If

 

  '复制找到的数据到found区域

  rgEntireItem.Copy rgDestination

 

  Set rgDestination = Nothing

  Set rgEntireItem = Nothing

End Sub

 

'初始化要复制到的区域(found区域)

Private Sub ReSetFoundList()

  Dim ws As Worksheet

  Dim lLastRow As Long

  Dim rgTopLeft As Range

  Dim rgBottomRight As Range

 

  Set ws = ThisWorkbook.Worksheets("sheet1")

  Set rgTopLeft = ws.Range("found").Offset(1, 0)

  lLastRow = ws.Range("found").End(xlDown).Row

  Set rgBottomRight = ws.Cells(lLastRow, rgTopLeft.Offset(0, 3).Column)

 

  ws.Range(rgTopLeft, rgBottomRight).ClearContents

 

  Set rgTopLeft = Nothing

  Set rgBottomRight = Nothing

  Set ws = Nothing

End Sub

'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

在上述程序代码中,程序FindSample2( )为主程序,首先调用子程序ReSetFoundList( )对所要复制到的数据区域初始化,即清空除标题行以外的内容;然后调用自定义函数GetSearchRange(ws As Worksheet)获取所在查找的单元格区域;在主程序中使用Find方法和FIndNext方法进行查找,调用带参数的子程序CopyItem(rgItem As Range)将查找到的单元格所在的数据行复制到相应的区域。

示例文档见 Find方法示例1.xlsUploadFiles/2006-9/928354714.rar

5.3 示例三:实现带连续单元格区域条件的查找

下面的代码提供了一种实现以连续单元格区域中的数据为查找条件进行查找的方法和思路。在本例中,所查找条件区域为D2:D4,在单元格区域A1:A21中进行查找,将结果输入到以单元格F2开始的区域中。示例程序所对应的工作表数据及结果如下图06所示。

'- - - - - - - - - -代码清单- - - - - - - - - - - - - - - - - - - - - -

Sub FindGroup()

  Dim ToFind As Range, Found As Range, c As Range

  Dim FirstAddress As String

  Set ToFind = Range("D2:D4")

  With Worksheets(1).Range("a1:a21")

    Set c = .Find(ToFind(1), LookIn:=xlValues)

    If Not c Is Nothing Then

      FirstAddress = c.Address

      Do

        If c.Offset(1) = ToFind(2) And c.Offset(2) = ToFind(3) Then

          Set Found = Range(c.Offset(0, 1), c.Offset(0, 1).Offset(2))

          GoTo Exits

        End If

        Set c = .FindNext(c)

      Loop While Not c Is Nothing And c.Address <> FirstAddress

    End If

  End With

Exits:

  Found.Copy Range("F2")

End Sub

'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  05 数据及查找结果

05 数据及查找结果

 

关于查找方法(Find方法)的应用()

--------------------------------------------------------------------------------

5.4 示例四:本示例所列程序将在工作簿的所有工作表中查找数值,提供了采用两种方法编写的程序,一种是Find方法,另一种是SpecialCells 方法。相对来说,使用Find方法比使用SpecialCells方法要快,当然,本示例可能不明显,但对于带大量工作表和数据的工作簿来说,这种速度差异就可以看出来了。(by fanjy from vbaexpress.com)

示例代码如下,代码中有简要的说明。

'- - -使用Find方法 - - - - - - - - - - - - - - - - - - - - - - - - - -

Sub QuickSearch()

  Dim wks As Excel.Worksheet

  Dim rCell As Excel.Range

  Dim szFirst As String

  Dim i As Long

  '设置变量决定是否加亮显示查找到的单元格

  '该变量为真时则加亮显示

  Dim bTag As Boolean

  bTag = True

  '使用input接受查找条件的输入

  Dim szLookupVal As String

  szLookupVal = InputBox("在下面的文本框中输入您想要查找的值", "查找输入框", "")

 

  '如果没有输入任何数据,则退出程序

  If szLookupVal = "" Then Exit Sub

   

   Application.ScreenUpdating = False

   Application.DisplayAlerts = False

       

  ' ================================================

  ' 添加一个工作表,在该工作表中放置已查找到的单元格地址

  ' 如果该工作表存在,则先删除它

    For Each wks In ActiveWorkbook.Worksheets

      If wks.Name = "查找结果" Then

        wks.Delete

      End If

    Next wks

    

  ' 添加工作表

    Sheets.Add ActiveSheet

  ' 重命名所添加的工作表

    ActiveSheet.Name = "查找结果"

  ' 在新增工作表中添加标题,指明所查找的值

    With Cells(1, 1)

      .Value = "已在下面所列出的位置找到数值" & szLookupVal

      .EntireColumn.AutoFit

      .HorizontalAlignment = xlCenter

    End With

 

  ' ================================================

  ' 定位到刚开始的工作表

    ActiveSheet.Next.Select

   

  ' ================================================

  ' 提示您是否想高亮显示已查找到的单元格

    If MsgBox("您想加阴影高亮显示所有查找到的单元格吗?", vbYesNo, _

              "加阴影高亮显示单元格") = vbNo Then

    ' 如果不想加阴影显示单元格,则将变量bTag值设置为False

      bTag = False

    End If

 

  ' ================================================

    i = 2

  ' 开始在工作簿的所有工作表中搜索

    For Each wks In ActiveWorkbook.Worksheets

  ' 检查所有的单元格,Find方法比SpecialCells方法更快

      With wks.Cells

        Set rCell = .Find(szLookupVal, , , xlWhole, xlByColumns, xlNext, False)

        If Not rCell Is Nothing Then

          szFirst = rCell.Address

          Do

           ' 添加找到的单元格地址到新工作表中

            rCell.Hyperlinks.Add Sheets("查找结果").Cells(i, 1), "", "'" & wks.Name & "'!" & rCell.Address

           '  检查条件判断值bTag,以决定是否加亮显示单元格

             Select Case bTag

                    Case True

                       rCell.Interior.ColorIndex = 19

             End Select

             Set rCell = .FindNext(rCell)

             i = i + 1

          Loop While Not rCell Is Nothing And rCell.Address <> szFirst

        End If

      End With

    Next wks

 

  ' 释放内存变量

    Set rCell = Nothing

   

  ' 如果没有找到匹配的值,则移除新增工作表

    If i = 2 Then

      MsgBox "您所要查找的数值{" & szLookupVal & "}在这些工作表中没有发现", 64, "没有匹配值"

      Sheets("查找结果").Delete

    End If

  

    Application.ScreenUpdating = True

    Application.DisplayAlerts = True

End Sub

 

'- - - 使用SpecialCells 方法- - - - - - - - - - - - - - - - - - - - - - - - -

Option Compare Text

Sub SlowerSearch()

    Dim wks As Excel.Worksheet

    Dim rCell As Excel.Range

    Dim i As Long

  '设置变量决定是否加亮显示查找到的单元格

  '该变量为真时则加亮显示

    Dim bTag As Boolean

    bTag = True

  '使用input接受查找条件的输入

    Dim szLookupVal As String

    szLookupVal = InputBox("在下面的文本框中输入您想要查找的值", "查找输入框", "")

 

  '如果没有输入任何数据,则退出程序

    If szLookupVal = "" Then Exit Sub

    With Application

      .ScreenUpdating = False

      .DisplayAlerts = False

      .Calculation = xlCalculationManual

         

  ' ==============================================

  ' 添加一个工作表,在该工作表中放置已查找到的单元格地址

  ' 如果该工作表存在,则先删除它

    For Each wks In ActiveWorkbook.Worksheets

      If wks.Name = "查找结果" Then

        wks.Delete

      End If

    Next wks

     

  ' 添加工作表

    Sheets.Add ActiveSheet

  ' 重命名所添加的工作表

    ActiveSheet.Name = "查找结果"

  ' 在新增工作表中添加标题,指明所查找的值

    With Cells(1, 1)

      .Value = "已在下面所列出的位置找到数值" & szLookupVal

      .EntireColumn.AutoFit

      .HorizontalAlignment = xlCenter

    End With

 

  ' ==========================================

  ' 定位到刚开始的工作表

    ActiveSheet.Next.Select

 

  ' ==========================================

    ' 提示您是否想高亮显示已查找到的单元格

    If MsgBox("您想加阴影高亮显示所有查找到的单元格吗?", vbYesNo, _

              "加阴影高亮显示单元格") = vbNo Then

    ' 如果不想加阴影显示单元格,则将变量bTag值设置为False

      bTag = False

    End If

  ' ==========================================

   i = 2

  ' 开始在工作簿的所有工作表中搜索

    On Error Resume Next

    For Each wks In ActiveWorkbook.Worksheets

      If wks.Cells.SpecialCells(xlCellTypeConstants).Count = 0 Then GoTo NoSpecCells

        For Each rCell In wks.Cells.SpecialCells(xlCellTypeConstants)

          DoEvents

          If rCell.Value = szLookupVal Then

           ' 添加找到的单元格地址到新工作表中

             rCell.Hyperlinks.Add Sheets("查找结果").Cells(i, 1), "", "'" & wks.Name & "'!" & rCell.Address

           '  检查条件判断值bTag,以决定是否加亮显示单元格

             Select Case bTag

                    Case True

                      rCell.Interior.ColorIndex = 19

             End Select

             i = i + 1

             .StatusBar = "查找到的单元格数为: " & i - 2

          End If

       Next rCell

NoSpecCells:

    Next wks

              

  ' 如果没有找到匹配的值,则移除新增工作表

  If i = 2 Then

    MsgBox "您所要查找的数值{" & szLookupVal & "}在这些工作表中没有发现", 64, "没有匹配值"

    Sheets("查找结果").Delete

  End If

 

  .Calculation = xlCalculationAutomatic

  .DisplayAlerts = True

  .ScreenUpdating = True

  .StatusBar = Empty

  End With

End Sub

'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

示例文档见 FindSpecialCells查找示例.xlshttp://blog./UploadFiles/2006-9/928569799.rar

--------------------------------------------------------------------------------

6. 其它一些查找方法

可以使用For Each Next语句和Like运算符进行更精确匹配的查找。例如,下列代码在单元格区域A1:A10中查找以字符“我”开头的单元格,并将其背景色变为红色。

'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Sub test()

  Dim Cell As Range

  For Each Cell In [A1:A10]

    If Cell Like "*" Then

        Cell.Interior.ColorIndex = 3

    End If

  Next

End Sub

'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

可以输入下图06所示的数据进行测试。

 06:测试的数据

 来源于:http://wenku.baidu.com/view/ba55b92c915f804d2b16c199.html

关于查找方法的应用示例:

[示例1]查找值并选中该值所在的单元格
[示例1-1]
Sub Find_First()
    Dim FindString As String
    Dim rng As Range
    FindString = InputBox("请输入要查找的值:")
    If Trim(FindString) <> "" Then
        With Sheets("Sheet1").Range("A:A")
            Set rng = .Find(What:=FindString, _
                            After:=.Cells(.Cells.Count), _
                            LookIn:=xlValues, _
                            LookAt:=xlWhole, _
                            SearchOrder:=xlByRows, _
                            SearchDirection:=xlNext, _
                            MatchCase:=False)
            If Not rng Is Nothing Then
                Application.Goto rng, True
            Else
                MsgBox "没有找到!"
            End If
        End With
    End If
End Sub
示例说明:运行程序后,将在工作表Sheet1的A列中查找InputBox函数输入框中所输入的值,并查找该值所在的第一个单元格,如果没有找到该值,则显示消息框“没有找到!”。语句Application.Goto rng, True的作用是将窗口滚动至该单元格,即该单元格位于当前窗口的左上方。
[示例1-2]
Sub Find_Last()
    Dim FindString As String
    Dim rng As Range
    FindString = InputBox("请输入要查找的值")
    If Trim(FindString) <> "" Then
        With Sheets("Sheet1").Range("A:A")
            Set rng = .Find(What:=FindString, _
                            After:=.Cells(1), _
                            LookIn:=xlValues, _
                            LookAt:=xlWhole, _
                            SearchOrder:=xlByRows, _
                            SearchDirection:=xlPrevious, _
                            MatchCase:=False)
            If Not rng Is Nothing Then
                Application.Goto rng, True
            Else
                MsgBox "Nothing found"
            End If
        End With
End If
示例说明:与上面的程序不同的是,运行该程序后,将在工作表Sheet1的A列中查找InputBox函数输入框中所输入的值,并选中该值所在的最后一个单元格。请比较代码中Find方法的参数。
[示例1-3]
Sub Find_Todays_Date()
    Dim FindString As Date
    Dim rng As Range
    FindString = Date
    With Sheets("Sheet1").Range("A:A")
        Set rng = .Find(What:=FindString, _
                        After:=.Cells(.Cells.Count), _
                        LookIn:=xlFormulas, _
                        LookAt:=xlWhole, _
                        SearchOrder:=xlByRows, _
                        SearchDirection:=xlNext, _
                        MatchCase:=False)
        If Not rng Is Nothing Then
            Application.Goto rng, True
        Else
            MsgBox "没有找到!"
        End If
    End With
End Sub
示例说明:运行程序后,将在工作表Sheet1的A列中查找日期所在的单元格,并选中第一个日期单元格。


[示例2]在B列中标出A列中有相应值的单元格
Sub Mark_cells_in_column()
    Dim FirstAddress As String
    Dim myArr As Variant
    Dim rng As Range
    Dim I As Long
 
    Application.ScreenUpdating = False
    myArr = Array("VBA")
   '也能够在数组中使用更多的值,如下所示
    'myArr = Array("VBA", "VSTO")
    With Sheets("Sheet2").Range("A:A")

 

        .Offset(0, 1).ClearContents
        '清除右侧单元格中的内容
 
        For I = LBound(myArr) To UBound(myArr)
            Set rng = .Find(What:=myArr(I), _
                            After:=.Cells(.Cells.Count), _
                            LookIn:=xlFormulas, _
                            LookAt:=xlWhole, _
                            SearchOrder:=xlByRows, _
                            SearchDirection:=xlNext, _
                            MatchCase:=False)
            '如要想查找rng.value中的一部分,可使用参数值xlPart
            '如果使用LookIn:=xlValues,也会处理公式单元格中与条件相同的值
 
            If Not rng Is Nothing Then
                FirstAddress = rng.Address
                Do
                    rng.Offset(0, 1).Value = "X"
                    '如果值VBA找到,则在该单元格的右侧列中的相应单元格作上标记
                    Set rng = .FindNext(rng)
                Loop While Not rng Is Nothing And rng.Address <> FirstAddress
            End If
        Next I
    End With
    Application.ScreenUpdating = True
End Sub
示例说明:运行程序后,将查找工作表Sheet2上A列中的每个单元格,并在值为“VBA”所在的单元格的右侧单元格中作出标记“X”。


[示例3]为区域中指定值的单元格填充颜色
Sub Color_cells_in_Range()
    Dim FirstAddress As String
    Dim MySearch As Variant
    Dim myColor As Variant
    Dim rng As Range
    Dim I As Long
 
    MySearch = Array("VBA")
    myColor = Array("3")
 
   '也能在数组中使用多个值
    'MySearch = Array("VBA", "Hello", "OK")
    'myColor = Array("3", "6", "10")
 
    With Sheets("Sheet3").Range("A1:C4")
 
        '将所有单元格中的填充色改为无填充色
        .Interior.ColorIndex = xlColorIndexNone
       
         For I = LBound(MySearch) To UBound(MySearch)
            Set rng = .Find(What:=MySearch(I), _
                            After:=.Cells(.Cells.Count), _
                            LookIn:=xlFormulas, _
                            LookAt:=xlWhole, _
                            SearchOrder:=xlByRows, _
                            SearchDirection:=xlNext, _
                            MatchCase:=False)
            '如果想查找rng.value的一部分,则使用参数值xlPart
            '如果使用LookIn:=xlValues,则也会处理公式单元格
 
            If Not rng Is Nothing Then
                FirstAddress = rng.Address
                Do
                    rng.Interior.ColorIndex = myColor(I)
                    Set rng = .FindNext(rng)
                Loop While Not rng Is Nothing And rng.Address <> FirstAddress
            End If
        Next I
    End With
End Sub
示例说明:运行程序后,将在工作表Sheet3上的单元格区域A1:C4中查找含有“VBA”的单元格,并将这些单元格填充为红色。如示例中的注释所提示的,也可以使用数组,将不同的值所在的单元格标记为不同的颜色。
也可以添加下面的语句,改变单元格中文本的颜色:
.Font.ColorIndex=0
.Font.ColorIndex=myColor(I)

[示例4]为工作表中指定值的单元格填充颜色
Sub Color_cells_in_Sheet()
    Dim FirstAddress As String
    Dim MySearch As Variant
    Dim myColor As Variant
    Dim rng As Range
    Dim I As Long
 
    MySearch = Array("VBA")
    myColor = Array("3")
 
    '也能在数组中使用多个值
    'MySearch = Array("VBA", "Hello", "OK")
    'myColor = Array("3", "6", "10")
 
    With Sheets("Sheet4").Cells
 
       '将所有单元格中的填充色改为无填充色
        .Interior.ColorIndex = xlColorIndexNone
 
        For I = LBound(MySearch) To UBound(MySearch)
            Set rng = .Find(What:=MySearch(I), _
                            After:=.Cells(.Cells.Count), _
                            LookIn:=xlFormulas, _
                            LookAt:=xlWhole, _
                            SearchOrder:=xlByRows, _
                            SearchDirection:=xlNext, _
                            MatchCase:=False)
           '如果想查找rng.value的一部分,则使用参数值xlPart
           '如果使用LookIn:=xlValues,则也会处理公式单元格
 
            If Not rng Is Nothing Then
                FirstAddress = rng.Address
                Do
                    rng.Interior.ColorIndex = myColor(I)
                    Set rng = .FindNext(rng)
                Loop While Not rng Is Nothing And rng.Address <> FirstAddress
            End If
        Next I
    End With
End Sub
示例说明:运行程序后,将在工作表Sheet4中查找含有“VBA”的单元格,并将这些单元格填充为红色。如示例中的注释所提示的,也可以使用数组,将不同的值所在的单元格标记为不同的颜色。
也可以添加下面的语句,改变单元格中文本的颜色:
.Font.ColorIndex=0
.Font.ColorIndex=myColor(I)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[示例5]为工作簿所有工作表中含有指定值的单元格填充颜色
Sub Color_cells_in_All_Sheets()
    Dim FirstAddress As String
    Dim MySearch As Variant
    Dim myColor As Variant
    Dim sh As Worksheet
    Dim rng As Range
    Dim I As Long
 
    MySearch = Array("ron")
    myColor = Array("3")
 
   '也能在数组中使用多个值
    'MySearch = Array("VBA", "Hello", "OK")
    'myColor = Array("3", "6", "10")
 
    For Each sh In ActiveWorkbook.Worksheets
        With sh.Cells
 
             '将所有单元格中的填充色改为无填充色
            .Interior.ColorIndex = xlColorIndexNone
 
            For I = LBound(MySearch) To UBound(MySearch)
                Set rng = .Find(What:=MySearch(I), _
                                After:=.Cells(.Cells.Count), _
                                LookIn:=xlFormulas, _
                                LookAt:=xlWhole, _
                                SearchOrder:=xlByRows, _
                                SearchDirection:=xlNext, _
                                MatchCase:=False)
                '如果想查找rng.value的一部分,则使用参数值xlPart
                '如果使用LookIn:=xlValues,则也会处理公式单元格
 
                If Not rng Is Nothing Then
                    FirstAddress = rng.Address
                    Do
                        rng.Interior.ColorIndex = myColor(I)
                        Set rng = .FindNext(rng)
                    Loop While Not rng Is Nothing And rng.Address <> FirstAddress
                End If
            Next I
        End With
    Next sh
End Sub
示例说明:运行程序后,将在工作簿所有工作表中查找含有“VBA”的单元格,并将这些单元格填充为红色。如示例中的注释所提示的,也可以使用数组,将不同的值所在的单元格标记为不同的颜色。
也可以添加下面的语句,改变单元格中文本的颜色:
.Font.ColorIndex=0
.Font.ColorIndex=myColor(I)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[示例6]复制相应的值到另一个工作表中
Sub Copy_To_Another_Sheet()
    Dim FirstAddress As String
    Dim MyArr As Variant
    Dim Rng As Range
    Dim Rcount As Long
    Dim I As Long
 
    Application.ScreenUpdating = False
   '也能够使用含有更多值的数组
    'myArr = Array("@", "www")
    MyArr = Array("@")
 
    Rcount = 0
    With Sheets("Sheet5").Range("A1:E10")
   
        For I = LBound(MyArr) To UBound(MyArr)
            '如果使用LookIn:=xlValues,也会处理含有"@"的公式单元格
            '注意:本示例使用xlPart而不是xlWhole
            Set Rng = .Find(What:=MyArr(I), _
                            After:=.Cells(.Cells.Count), _
                            LookIn:=xlFormulas, _
                            LookAt:=xlPart, _
                            SearchOrder:=xlByRows, _
                            SearchDirection:=xlNext, _
                            MatchCase:=False)
            If Not Rng Is Nothing Then
                FirstAddress = Rng.Address
                Do
                    Rcount = Rcount + 1
                    '仅复制值
                    Sheets("Sheet6").Range("A" & Rcount).Value = Rng.Value
                    Set Rng = .FindNext(Rng)
                Loop While Not Rng Is Nothing And Rng.Address <> FirstAddress
            End If
        Next I
    End With
示例说明:运行程序后,将在工作表Sheet5的单元格区域A1:E10中查找带有“@”的单元格,即e-mail地址,然后将这些单元格值依次复制到工作表Sheet6的A列中。注意,本例中使用参数值为xlPart,并且仅复制单元格值,即不带格式。
 
在VBA中使用Find方法(扩展用法)
引言:本文是《关于查找方法(Find方法)的应用》和《关于查找方法(Find方法)的应用示例补充》的继续,介绍了Find方法的一些扩展技术。
使用VBA在工作表或单元格区域中查找某项数据时,我们通常使用For…Next循环,这在小范围中使用还可以,但应用在大量数据中查找时,会耗费较多时间。
而在Excel工作表中,通常使用菜单“编辑>>查找”命令或按Ctrl+F组合键,在“查找和替换”对话框中来迅速查找所需的数据。在VBA中,我们也能使用这种方法,这在下面的内容中介绍。
为什么要使用Find方法呢?最主要的原因是查找的速度。如果要使用VBA代码在包含大量数据的单元格区域中查找某项数据,应该使用Find方法。
例如,在工作表Sheet1的单元格IV65536中输入fanjy,然后运行下面的代码:
Sub QuickSearch()
    If Not Sheet1.Cells.Find("fanjy") Is Nothing Then MsgBox "已找到fanjy!"
End Sub
再试试下面的代码:
Sub SlowSearch()
    Dim R As Range
    For Each R In Sheet1.Cells
        If R.Value = "fanjy" Then MsgBox "已找到fanjy!"
    Next R
End Sub
比较一下两段代码的速度,可知第一段代码运行很快,而第二段代码却要执行相当长的一段时间。
关于Find方法的基本使用方法请见《关于查找方法(Find方法)的应用》。下面介绍一些扩展Find方法的技术。
我们能够使用Find方法查找单元格区域的数据,但是没有一个方法能够返回一个Range对象,该对象引用了含有所查找数据的所有单元格,下面提供了一个FindAll函数来实现此功能。此外,Find方法的另一个不足之处是不支持通配符字符串,下面也提供了一个WildCardMatchCells函数,返回一个Range对象,引用了与所提供的通配符字符串相匹配的单元格。通配符字符串可以是有效使用在Like运算符中的任何字符串,关于Like运算符的介绍请见《关于Like运算符的使用》一文。
- - - - - - - - - - - - - - - - - - - - -
FindAll函数
这个程序在参数SearchRange所代表的区域中查找所有含有参数FindWhat代表的值的单元格,SearchRange参数必须是一个单独的单元格区域对象,FindWhat参数是想要查找的值,其它参数是可选的且与Find方法的参数意思相同。
FindAll函数的代码如下:
Option Compare Text
Function FindAll(SearchRange As Range, FindWhat As Variant, _
    Optional LookIn As XlFindLookIn = xlValues, Optional LookAt As XlLookAt = xlWhole, _
    Optional SearchOrder As XlSearchOrder = xlByRows, _
    Optional MatchCase As Boolean = False) As Range
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 返回SearchRange区域中含有FindWhat所代表的值的所有单元格组成的Range对象
' 其参数与Find方法的参数相同
' 如果没有找到单元格,将返回Nothing.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  Dim FoundCell As Range
  Dim FoundCells As Range
  Dim LastCell As Range
  Dim FirstAddr As String
  With SearchRange
    Set LastCell = .Cells(.Cells.Count)
  End With
  Set FoundCell = SearchRange.Find(what:=FindWhat, after:=LastCell, _
    LookIn:=LookIn, LookAt:=LookAt, SearchOrder:=SearchOrder, MatchCase:=MatchCase)
  If Not FoundCell Is Nothing Then
    Set FoundCells = FoundCell
    FirstAddr = FoundCell.Address
    Do
      Set FoundCells = Application.Union(FoundCells, FoundCell)
      Set FoundCell = SearchRange.FindNext(after:=FoundCell)
    Loop Until (FoundCell Is Nothing) Or (FoundCell.Address = FirstAddr)
  End If
  If FoundCells Is Nothing Then
    Set FindAll = Nothing
  Else
    Set FindAll = FoundCells
  End If
End Function
使用上面代码的示例:
Sub TestFindAll()
    Dim SearchRange As Range
    Dim FoundCells As Range
    Dim FoundCell As Range
    Dim FindWhat As Variant
    Dim MatchCase As Boolean
    Dim LookIn As XlFindLookIn
    Dim LookAt As XlLookAt
    Dim SearchOrder As XlSearchOrder
   
    Set SearchRange = ThisWorkbook.Worksheets(1).Range("A1:L20")
    FindWhat = "A" '要查找的文本,可根据实际情况自定
    LookIn = xlValues
    LookAt = xlPart
    SearchOrder = xlByRows
    MatchCase = False
   
    Set FoundCells = FindAll(SearchRange:=SearchRange, FindWhat:=FindWhat, _
        LookIn:=LookIn, LookAt:=LookAt, SearchOrder:=SearchOrder, MatchCase:=MatchCase)
   
    If FoundCells Is Nothing Then
        Debug.Print "没有找到!"
    Else
        For Each FoundCell In FoundCells.Cells
            Debug.Print FoundCell.Address, FoundCell.Text
        Next FoundCell
    End If
   
End Sub
上面的代码中,列出了查找区域中含有所要查找的数据的所有单元格的地址以及相应文本。不仅可以找出所有含有所查找数据的单元格地址,而且也可以对这些单元格进行一系列操作,如格式化、更改数据等。
- - - - - - - - - - - - - - - - - - - - -
WildCardMatchCells函数
这个程序查找参数SearchRange所代表的区域中所有单元格,使用Like运算符将它们的值与参数CompareLikeString所代表的值比较。参数SearchRange必须是一个单独的区域,参数CompareLikeString是想要比较的文本的格式。该函数使用单元格的Text属性而不是Value属性。可选参数SearchOrder和MatchCase与Find方法中的参数意义相同。
该函数返回一个Range对象,该对象包含对与参数CompareLikeString相匹配的所有单元格的引用。如果没有匹配的单元格,则返回Nothing。
因为Find方法不支持通配符,程序将循环所有的单元格,因此对于包含大量数据的区域,执行时间可能是一个问题。并且,如果参数MatchCase为False或忽略该参数,文本在程序中必须被转换成大写,以便于查找时不区分大小写(即“A”=“a”),因此,此时程序运行将更慢。
WildCardMatchCells函数的代码如下:
Function WildCardMatchCells(SearchRange As Range, CompareLikeString As String, _
    Optional SearchOrder As XlSearchOrder = xlByRows, _
    Optional MatchCase As Boolean = False) As Range
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 本程序返回文本值与通配符字符串相匹配的单元格引用
' 返回SearchRange区域中所有相匹配的单元格
' 匹配的条件是参数CompareLikeString
' 使用了VBA中的LIKE运算符
' 如果没有相匹配的单元格或指定了一个无效的参数,则返回Nothing.
'
' 参数SearchOrder指定查找的方向;逐行还是逐列(SearchOrder:=xlByRows或SearchOrder:=xlByColumns
' 参数MatchCase指定是否区分大小写(MatchCase:=True, "A" <> "a")或(MatchCase:=False,"A" = "a").
'
' 不需要在模块顶指定"Option Compare Text",如果指定的话,将不会正确执行大小写比较
'
' 执行单元格中的Text属性比较,而不是Value属性比较
' 因此,仅比较显示在屏幕中的文本,而不是隐藏在单元格中具体的值
'
' 如果参数SearchRange是nothing或多个区域,则返回Nothing.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  Dim FoundCells As Range
  Dim FirstCell As Range
  Dim LastCell As Range
  Dim RowNdx As Long
  Dim ColNdx As Long
  Dim StartRow As Long
  Dim EndRow As Long
  Dim StartCol As Long
  Dim EndCol As Long
  Dim WS As Worksheet
  Dim Rng As Range

' 确保参数SearchRange不是Nothing且是一个单独的区域
  If SearchRange Is Nothing Then
    Exit Function
  End If
  If SearchRange.Areas.Count > 1 Then
    Exit Function
  End If

  With SearchRange
    Set WS = .Worksheet
    Set FirstCell = .Cells(1)
    Set LastCell = .Cells(.Cells.Count)
  End With

  StartRow = FirstCell.Row
  StartCol = FirstCell.Column
  EndRow = LastCell.Row
  EndCol = LastCell.Column

  If SearchOrder = xlByRows Then
    With WS
      For RowNdx = StartRow To EndRow
        For ColNdx = StartCol To EndCol
          Set Rng = .Cells(RowNdx, ColNdx)
            If MatchCase = False Then
             '''''''''''''''''''''''''''''''''''
             '如果参数MatchCase是False,则将字符串转换成大写
             '执行忽略大小写的比较
             '因此,MatchCase:=False比MatchCase:=True更慢
             '''''''''''''''''''''''''''''''''''
               If UCase(Rng.Text) Like UCase(CompareLikeString) Then
                 If FoundCells Is Nothing Then
                    Set FoundCells = Rng
                 Else
                    Set FoundCells = Application.Union(FoundCells, Rng)
                 End If
               End If
              Else
                ''''''''''''''''''''''''''''''''''''''''''''''''
                ' MatchCase为真,不需要再进行大小写转换,因此更快些
                ' 这也是不需要在模块中指定"Option Compare Text"的原因
                ''''''''''''''''''''''''''''''''''''''''''''''''
                If Rng.Text Like CompareLikeString Then
                  If FoundCells Is Nothing Then
                    Set FoundCells = Rng
                  Else
                    Set FoundCells = Application.Union(FoundCells, Rng)
                  End If
                End If
            End If
        Next ColNdx
      Next RowNdx
    End With
  Else
    With WS
      For ColNdx = StartCol To EndCol
        For RowNdx = StartRow To EndRow
          Set Rng = .Cells(RowNdx, ColNdx)
          If MatchCase = False Then
            If UCase(Rng.Text) Like UCase(CompareLikeString) Then
              If FoundCells Is Nothing Then
                Set FoundCells = Rng
              Else
                Set FoundCells = Application.Union(FoundCells, Rng)
              End If
            End If
          Else
            If Rng.Text Like CompareLikeString Then
              If FoundCells Is Nothing Then
                Set FoundCells = Rng
              Else
                Set FoundCells = Application.Union(FoundCells, Rng)
              End If
            End If
          End If
        Next RowNdx
      Next ColNdx
    End With
  End If

  If FoundCells Is Nothing Then
    Set WildCardMatchCells = Nothing
  Else
    Set WildCardMatchCells = FoundCells
  End If
End Function
使用上面代码的示例:
Sub TestWildCardMatchCells()
    Dim SearchRange As Range
    Dim FoundCells As Range
    Dim FoundCell As Range
    Dim CompareLikeString As String
    Dim SearchOrder As XlSearchOrder
    Dim MatchCase As Boolean
   
    Set SearchRange = Range("A1:IV65000")
    CompareLikeString = "A?C*"
    SearchOrder = xlByRows
    MatchCase = True
   
    Set FoundCells = WildCardMatchCells(SearchRange:=SearchRange, CompareLikeString:=CompareLikeString, _
        SearchOrder:=SearchOrder, MatchCase:=MatchCase)
    If FoundCells Is Nothing Then
        Debug.Print "没有找到!"
    Else
        For Each FoundCell In FoundCells
          Debug.Print FoundCell.Address, FoundCell.Text
        Next FoundCell
    End If
End Sub
这样,在找到所需单元格后,就可以对这些单元格进行操作了。
注:本文整理自The Code Net和Chip Pearson的文章。
分类:ExcelVBA>>ExcelVBA对象模型编程>>常用对象>>Range对象
By fanjy in 2007-2-11

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多