




本文整理了以前的一些關(guān)于Find方法的文章,作為Excel VBA應(yīng)用大全的一部分。
1. Find方法的作用
使用VBA在工作表或單元格區(qū)域中查找某項(xiàng)數(shù)據(jù)時(shí),我們通常使用For…Next循環(huán),這在小范圍中使用還可以,但應(yīng)用在大量數(shù)據(jù)中查找時(shí),會(huì)耗費(fèi)較多時(shí)間。
而在Excel工作表中,通常使用菜單“編輯>>查找”命令或按Ctrl+F組合鍵,在“查找和替換”對話框中來迅速查找所需的數(shù)據(jù)。在VBA中,我們也能使用這種方法,即Find方法,這在下面的內(nèi)容中介紹。
Find方法將在指定的單元格區(qū)域中查找包含參數(shù)指定數(shù)據(jù)的單元格,若找到符合條件的數(shù)據(jù),則返回包含該數(shù)據(jù)的單元格;若未發(fā)現(xiàn)相匹配的數(shù)據(jù),則返回Nothing。該方法返回一個(gè)Range對象,在使用該方法時(shí),不影響選定區(qū)域或活動(dòng)單元格。
為什么要使用Find方法呢?最主要的原因是查找的速度。如果要使用VBA代碼在包含大量數(shù)據(jù)的單元格區(qū)域中查找某項(xiàng)數(shù)據(jù),應(yīng)該使用Find方法。
例如,在工作表Sheet1的單元格IV65536中輸入fanjy,然后運(yùn)行下面的代碼:
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
比較一下兩段代碼的速度,可知第一段代碼運(yùn)行很快,而第二段代碼卻要執(zhí)行相當(dāng)長的一段時(shí)間。
2. Find方法的語法
[語法]
<單元格區(qū)域>.Find (What,[After],[LookIn],[LookAt],[SearchOrder],[SearchDirection],[MatchCase],[MatchByte],[SearchFormat])
[參數(shù)說明]
(1)<單元格區(qū)域>,必須指定,返回一個(gè)Range對象。
(2)參數(shù)What,必需指定。代表所要查找的數(shù)據(jù),可以為字符串、整數(shù)或者其它任何數(shù)據(jù)類型的數(shù)據(jù)。對應(yīng)于“查找與替換”對話框中,“查找內(nèi)容”文本框中的內(nèi)容。
(3)參數(shù)After,可選。指定開始查找的位置,即從該位置所在的單元格之后向后或之前向前開始查找(也就是說,開始時(shí)不查找該位置所在的單元格,直到
Find方法繞回到該單元格時(shí),才對其內(nèi)容進(jìn)行查找)。所指定的位置必須是單元格區(qū)域中的單個(gè)單元格,如果未指定本參數(shù),則將從單元格區(qū)域的左上角的單元
格之后開始進(jìn)行查找。
(4)參數(shù)LookIn,可選。指定查找的范圍類型,可以為以下常量之一:xlValues、xlFormulas或者xlComments,默認(rèn)值為xlFormulas。對應(yīng)于“查找與替換”對話框中,“查找范圍”下拉框中的選項(xiàng)。
(5)參數(shù)LookAt,可選。可以為以下常量之一:XlWhole或者xlPart,用來指定所查找的數(shù)據(jù)是與單元格內(nèi)容完全匹配還是部分匹配,默認(rèn)值為xlPart。對應(yīng)于“查找與替換”對話框中,“單元格匹配”復(fù)選框。
(6)參數(shù)SearchOrder,可選。用來確定如何在單元格區(qū)域中進(jìn)行查找,是以行的方式(xlByRows)查找,還是以列的方式(xlByColumns)查找,默認(rèn)值為xlByRows。對應(yīng)于“查找與替換”對話框中,“搜索”下拉框中的選項(xiàng)。
(7)參數(shù)SearchDirection,可選。用來確定查找的方向,即是向前查找(XlPrevious)還是向后查找(xlNext),默認(rèn)的是向后查找。
(8)參數(shù)MatchCase,可選。若該參數(shù)值為True,則在查找時(shí)區(qū)分大小寫。默認(rèn)值為False。對應(yīng)于“查找與替換”對話框中,“區(qū)分大小寫”復(fù)選框。
(9)參數(shù)MatchByter,可選。即是否區(qū)分全角或半角,在選擇或安裝了雙字節(jié)語言時(shí)使用。若該參數(shù)為True,則雙字節(jié)字符僅與雙字節(jié)字符相匹
配;若該參數(shù)為False,則雙字節(jié)字符可匹配與其相同的單字節(jié)字符。對應(yīng)于“查找與替換”對話框中,“區(qū)分全角/半角”復(fù)選框。
(10)參數(shù)SearchFormat,可選,指定一個(gè)確切類型的查找格式。對應(yīng)于“查找與替換”對話框中,“格式”按鈕。當(dāng)設(shè)置帶有相應(yīng)格式的查找時(shí),該參數(shù)值為True。
(11)在每次使用Find方法后,參數(shù)LookIn、LookAt、SearchOrder、MatchByte的設(shè)置將保存。如果下次使用本方法時(shí),不改變或指定這些參數(shù)的值,那么該方法將使用保存的值。
在VBA中設(shè)置的這些參數(shù)將更改“查找與替換”對話框中的設(shè)置;同理,更改“查找與替換”對話框中的設(shè)置,也將同時(shí)更改已保存的值。也就是說,在編寫好一
段代碼后,若在代碼中未指定上述參數(shù),可能在初期運(yùn)行時(shí)能滿足要求,但若用戶在“查找與替換”對話框中更改了這些參數(shù),它們將同時(shí)反映到程序代碼中,當(dāng)再
次運(yùn)行代碼時(shí),運(yùn)行結(jié)果可能會(huì)產(chǎn)生差異或錯(cuò)誤。若要避免這個(gè)問題,在每次使用時(shí)建議明確的設(shè)置這些參數(shù)。
3. Find方法使用示例
3.1 本示例在活動(dòng)工作表中查找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 帶格式的查找
本示例在當(dāng)前工作表單元格中查找字體為”Arial Unicode MS”且顏色為紅色的單元格。其中,Application.FindFormat對象允許指定所需要查找的格式,此時(shí)Find方法的參數(shù)SearchFormat應(yīng)設(shè)置為True。
Sub FindWithFormat() With Application.FindFormat.Font .Name = "Arial Unicode MS" .ColorIndex = 3 End With Cells.Find(what:="", SearchFormat:=True).Activate End Sub
[小結(jié)] 在使用Find方法找到符合條件的數(shù)據(jù)后,就可以對其進(jìn)行相應(yīng)的操作了。您可以:
- 對該數(shù)據(jù)所在的單元格進(jìn)行操作;
- 對該數(shù)據(jù)所在單元格的行或列進(jìn)行操作;
- 對該數(shù)據(jù)所在的單元格區(qū)域進(jìn)行操作。
4. 與Find方法相聯(lián)系的方法
可以使用FindNext方法和FindPrevious方法進(jìn)行重復(fù)查找。在使用這兩個(gè)方法之前,必須用Find方法指定所需要查找的數(shù)據(jù)內(nèi)容。
4.1 FindNext方法
FindNext方法對應(yīng)于“查找與替換”對話框中的“查找下一個(gè)”按鈕。可以使用該方法繼續(xù)執(zhí)行查找,查找下一個(gè)與Find方法中所指定條件的數(shù)據(jù)相匹配的單元格,返回代表該單元格的Range對象。在使用該方法時(shí),不影響選定區(qū)域或活動(dòng)單元格。
4.1.1 語法
<單元格區(qū)域>.FindNext(After)
4.1.2 參數(shù)說明
參數(shù)After,可選。代表所指定的單元格,將從該單元格之后開始進(jìn)行查找。開始時(shí)不查找該位置所在的單元格,直到FindNext方法繞回到該單元格
時(shí),才對其內(nèi)容進(jìn)行查找。所指定的位置必須是單元格區(qū)域中的單個(gè)單元格,如果未指定本參數(shù),則將從單元格區(qū)域的左上角的單元格之后開始進(jìn)行查找。
當(dāng)查找到指定查找區(qū)域的末尾時(shí),本方法將環(huán)繞至區(qū)域的開始繼續(xù)查找。發(fā)生環(huán)繞后,為停止查找,可保存第一次找到的單元格地址,然后測試下一個(gè)查找到的單元
格地址是否與其相同,作為判斷查找退出的條件,以避免出現(xiàn)死循環(huán)。當(dāng)然,如果在查找的過程中,將查找到的單元格數(shù)據(jù)進(jìn)行了改變,也可不作此判斷,如下例所
示。
4.2 FindPrevious方法
可以使用該方法繼續(xù)執(zhí)行Find方法所進(jìn)行的查找,查找前一個(gè)與Find方法中所指定條件的數(shù)據(jù)相匹配的單元格,返回代表該單元格的Range對象。在使用該方法時(shí),不影響選定區(qū)域或活動(dòng)單元格。
4.2.1 語法
<單元格區(qū)域>.FindPrevious(After)
4.2.2 參數(shù)說明
參數(shù)After,可選。代表所指定的單元格,將從該單元格之前開始進(jìn)行查找。開始時(shí)不查找該位置所在的單元格,直到FindPrevious方法繞回到該
單元格時(shí),才對其內(nèi)容進(jìn)行查找。所指定的位置必須是單元格區(qū)域中的單個(gè)單元格,如果未指定本參數(shù),則將從單元格區(qū)域的左上角的單元格之前開始進(jìn)行查找。
當(dāng)查找到指定查找區(qū)域的起始位置時(shí),本方法將環(huán)繞至區(qū)域的末尾繼續(xù)查找。發(fā)生環(huán)繞后,為停止查找,可保存第一次找到的單元格地址,然后測試下一個(gè)查找到的單元格地址是否與其相同,作為判斷查找退出的條件,以避免出現(xiàn)死循環(huán)。
4.2.3 示例
在工作表中輸入如下圖1所示的數(shù)據(jù),至少保證在A列中有兩個(gè)單元格輸入了數(shù)據(jù)“excelhome”。
圖1:測試的數(shù)據(jù)
在VBE編輯器中輸入下面的代碼測試Find方法、FindNext方法、FindPrevious方法,體驗(yàn)各個(gè)方法所查找到的單元格位置。
Sub testFind() Dim findValue As Range Set findValue = Worksheets("Sheet1").Columns("A").Find(what:="excelhome") MsgBox "第一個(gè)數(shù)據(jù)發(fā)現(xiàn)在單元格:" & findValue.Address Set findValue = Worksheets("Sheet1").Columns("A").FindNext(After:=findValue) MsgBox "下一個(gè)數(shù)據(jù)發(fā)現(xiàn)在單元格:" & findValue.Address Set findValue = Worksheets("Sheet1").Columns("A").FindPrevious(After:=findValue) MsgBox "前一個(gè)數(shù)據(jù)發(fā)現(xiàn)在單元格" & findValue.Address End Sub
5. 綜合示例
[示例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
示例說明:運(yùn)行程序后,將在工作表Sheet1的A列中查找InputBox函數(shù)輸入框中所輸入的值,并查找該值所在的第一個(gè)單元格,如果沒有找到
該值,則顯示消息框“沒有找到!”。語句Application.Goto rng,
True的作用是將窗口滾動(dòng)至該單元格,即該單元格位于當(dāng)前窗口的左上方。
[示例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 End Sub
示例說明:與上面的程序不同的是,運(yùn)行該程序后,將在工作表Sheet1的A列中查找InputBox函數(shù)輸入框中所輸入的值,并選中該值所在的最后一個(gè)單元格。請比較代碼中Find方法的參數(shù)。
[示例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
示例說明:運(yùn)行程序后,將在工作表Sheet1的A列中查找日期所在的單元格,并選中第一個(gè)日期單元格。
[示例2]在B列中標(biāo)出A列中有相應(yīng)值的單元格
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") '也能夠在數(shù)組中使用更多的值,如下所示 'myArr = Array("VBA", "VSTO") With Sheets("Sheet2").Range("A:A") .Offset(0, 1).ClearContents '清除右側(cè)單元格中的內(nèi)容 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中的一部分,可使用參數(shù)值xlPart '如果使用LookIn:=xlValues,也會(huì)處理公式單元格中與條件相同的值 If Not rng Is Nothing Then FirstAddress = rng.Address Do rng.Offset(0, 1).Value = "X" '如果值VBA找到,則在該單元格的右側(cè)列中的相應(yīng)單元格作上標(biāo)記 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
示例說明:運(yùn)行程序后,將查找工作表Sheet2上A列中的每個(gè)單元格,并在值為“VBA”所在的單元格的右側(cè)單元格中作出標(biāo)記“X”。
[示例3]為區(qū)域中指定值的單元格填充顏色
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") '也能在數(shù)組中使用多個(gè)值 '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的一部分,則使用參數(shù)值xlPart '如果使用LookIn:=xlValues,則也會(huì)處理公式單元格 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
示例說明:運(yùn)行程序后,將在工作表Sheet3上的單元格區(qū)域A1:C4中查找含有“VBA”的單元格,并將這些單元格填充為紅色。如示例中的注釋所提示的,也可以使用數(shù)組,將不同的值所在的單元格標(biāo)記為不同的顏色。
也可以添加下面的語句,改變單元格中文本的顏色:
.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") '也能在數(shù)組中使用多個(gè)值 '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的一部分,則使用參數(shù)值xlPart '如果使用LookIn:=xlValues,則也會(huì)處理公式單元格 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
示例說明:運(yùn)行程序后,將在工作表Sheet4中查找含有“VBA”的單元格,并將這些單元格填充為紅色。如示例中的注釋所提示的,也可以使用數(shù)組,將不同的值所在的單元格標(biāo)記為不同的顏色。
也可以添加下面的語句,改變單元格中文本的顏色:
.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") '也能在數(shù)組中使用多個(gè)值 '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的一部分,則使用參數(shù)值xlPart '如果使用LookIn:=xlValues,則也會(huì)處理公式單元格 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
示例說明:運(yùn)行程序后,將在工作簿所有工作表中查找含有“VBA”的單元格,并將這些單元格填充為紅色。如示例中的注釋所提示的,也可以使用數(shù)組,將不同的值所在的單元格標(biāo)記為不同的顏色。
也可以添加下面的語句,改變單元格中文本的顏色:
.Font.ColorIndex=0 .Font.ColorIndex=myColor(I)
[示例6]復(fù)制相應(yīng)的值到另一個(gè)工作表中
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 '也能夠使用含有更多值的數(shù)組 'myArr = Array("@", "www") MyArr = Array("@") Rcount = 0 With Sheets("Sheet5").Range("A1:E10") For I = LBound(MyArr) To UBound(MyArr) '如果使用LookIn:=xlValues,也會(huì)處理含有"@"的公式單元格 '注意:本示例使用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 '僅復(fù)制值 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 End Sub
示例說明:運(yùn)行程序后,將在工作表Sheet5的單元格區(qū)域A1:E10中查找?guī)в小癅”的單元格,即e-mail地址,然后將這些單元格值依次復(fù)制到工作表Sheet6的A列中。注意,本例中使用參數(shù)值為xlPart,并且僅復(fù)制單元格值,即不帶格式。
[示例7]在當(dāng)前工作表的單元格區(qū)域A1:A50中輸入數(shù)據(jù)5和其它的一些數(shù)據(jù),然后在VBE編輯器中輸入下面的代碼。運(yùn)行后,程序?qū)⒃趩卧馎1:A50區(qū)域中查找數(shù)值5所在的單元格,并在所找到的單元格中畫一個(gè)藍(lán)色的橢圓。
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
[示例8]在一個(gè)列表中復(fù)制相關(guān)數(shù)據(jù)到另一個(gè)列表
本程序的功能是,根據(jù)單元格I1中的值,在單元格區(qū)域A1:D11中的B列進(jìn)行查找,每次找到相應(yīng)的值,就將該單元格所在區(qū)域的行數(shù)據(jù)復(fù)制到以單元格G3(該單元格命名為found)開始的區(qū)域中。原數(shù)據(jù)如下圖2所示。
圖2:原始數(shù)據(jù)
點(diǎn)擊工作表中的“查找”按鈕,運(yùn)行后的結(jié)果如下圖3所示。
圖3:運(yùn)行后的結(jié)果
源程序代碼清單及相關(guān)說明如下:
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 '初始化要復(fù)制的列表區(qū)域 Set ws = ThisWorkbook.Worksheets("sheet1") bContinue = True Set rgSearchIn = GetSearchRange(ws) '獲取查找區(qū)域 '設(shè)置查找參數(shù) Set rgFound = rgSearchIn.Find(what:=ws.Range("I1").Value, _ LookIn:=xlValues, LookAt:=xlWhole) '獲取第一個(gè)滿足條件的單元格地址,作為結(jié)束循環(huán)的條件 If Not rgFound Is Nothing Then sFirstFound = rgFound.Address Do Until rgFound Is Nothing Or Not bContinue CopyItem rgFound Set rgFound = rgSearchIn.FindNext(rgFound) '判斷循環(huán)是否中止 If rgFound.Address = sFirstFound Then bContinue = False Loop Set rgSearchIn = Nothing Set rgFound = Nothing Set ws = Nothing End Sub '獲取查找區(qū)域,即B列中的"部位"單元格區(qū)域 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 '復(fù)制查找到的數(shù)據(jù)到found區(qū)域 Private Sub CopyItem(rgItem As Range) Dim rgDestination As Range Dim rgEntireItem As Range '獲取在查找區(qū)域中的整行數(shù)據(jù) Set rgEntireItem = rgItem.Offset(0, -1) Set rgEntireItem = rgEntireItem.Resize(1, 4) Set rgDestination = rgItem.Parent.Range("found") '定位要復(fù)制到的found區(qū)域的第一行 If IsEmpty(rgDestination.Offset(1, 0)) Then Set rgDestination = rgDestination.Offset(1, 0) Else Set rgDestination = rgDestination.End(xlDown).Offset(1, 0) End If '復(fù)制找到的數(shù)據(jù)到found區(qū)域 rgEntireItem.Copy rgDestination Set rgDestination = Nothing Set rgEntireItem = Nothing End Sub '初始化要復(fù)制到的區(qū)域(found區(qū)域) 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( )為主程序,首先調(diào)用子程序ReSetFoundList(
)對所要復(fù)制到的數(shù)據(jù)區(qū)域初始化,即清空除標(biāo)題行以外的內(nèi)容;然后調(diào)用自定義函數(shù)GetSearchRange(ws As
Worksheet)獲取所在查找的單元格區(qū)域;在主程序中使用Find方法和FIndNext方法進(jìn)行查找,調(diào)用帶參數(shù)的子程序
CopyItem(rgItem As Range)將查找到的單元格所在的數(shù)據(jù)行復(fù)制到相應(yīng)的區(qū)域。
[示例9]實(shí)現(xiàn)帶連續(xù)單元格區(qū)域條件的查找
下面的代碼提供了一種實(shí)現(xiàn)以連續(xù)單元格區(qū)域中的數(shù)據(jù)為查找條件進(jìn)行查找的方法和思路。在本例中,所查找條件區(qū)域?yàn)镈2:D4,在單元格區(qū)域A1:A21中進(jìn)行查找,將結(jié)果輸入到以單元格F2開始的區(qū)域中。示例程序所對應(yīng)的工作表數(shù)據(jù)及結(jié)果如下圖4所示。
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
圖4:數(shù)據(jù)及查找結(jié)果
[示例10]本示例所列程序?qū)⒃诠ぷ鞑镜乃泄ぷ鞅碇胁檎覕?shù)值,提供了采用兩種方法編寫的程序,一種是Find方法,
另一種是SpecialCells
方法。相對來說,使用Find方法比使用SpecialCells方法要快,當(dāng)然,本示例可能不明顯,但對于帶大量工作表和數(shù)據(jù)的工作簿來說,這種速度差
異就可以看出來了。
示例代碼如下,代碼中有簡要的說明。
'- - -使用Find方法 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Sub QuickSearch() Dim wks As Excel.Worksheet Dim rCell As Excel.Range Dim szFirst As String Dim i As Long '設(shè)置變量決定是否加亮顯示查找到的單元格 '該變量為真時(shí)則加亮顯示 Dim bTag As Boolean bTag = True '使用input接受查找條件的輸入 Dim szLookupVal As String szLookupVal = InputBox("在下面的文本框中輸入您想要查找的值", "查找輸入框", "") '如果沒有輸入任何數(shù)據(jù),則退出程序 If szLookupVal = "" Then Exit Sub Application.ScreenUpdating = False Application.DisplayAlerts = False ' ============================================================= ' 添加一個(gè)工作表,在該工作表中放置已查找到的單元格地址 ' 如果該工作表存在,則先刪除它 For Each wks In ActiveWorkbook.Worksheets If wks.Name = "查找結(jié)果" Then wks.Delete End If Next wks ' 添加工作表 Sheets.Add ActiveSheet ' 重命名所添加的工作表 ActiveSheet.Name = "查找結(jié)果" ' 在新增工作表中添加標(biāo)題,指明所查找的值 With Cells(1, 1) .Value = "已在下面所列出的位置找到數(shù)值" & szLookupVal .EntireColumn.AutoFit .HorizontalAlignment = xlCenter End With ' ============================================================= ' 定位到剛開始的工作表 ActiveSheet.Next.Select ' ============================================================= ' 提示您是否想高亮顯示已查找到的單元格 If MsgBox("您想加陰影高亮顯示所有查找到的單元格嗎?", vbYesNo, _ "加陰影高亮顯示單元格") = vbNo Then ' 如果不想加陰影顯示單元格,則將變量bTag值設(shè)置為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("查找結(jié)果").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 ' 釋放內(nèi)存變量 Set rCell = Nothing ' 如果沒有找到匹配的值,則移除新增工作表 If i = 2 Then MsgBox "您所要查找的數(shù)值{" & szLookupVal & "}在這些工作表中沒有發(fā)現(xiàn)", 64, "沒有匹配值" Sheets("查找結(jié)果").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 '設(shè)置變量決定是否加亮顯示查找到的單元格 '該變量為真時(shí)則加亮顯示 Dim bTag As Boolean bTag = True '使用input接受查找條件的輸入 Dim szLookupVal As String szLookupVal = InputBox("在下面的文本框中輸入您想要查找的值", "查找輸入框", "") '如果沒有輸入任何數(shù)據(jù),則退出程序 If szLookupVal = "" Then Exit Sub With Application .ScreenUpdating = False .DisplayAlerts = False .Calculation = xlCalculationManual ' ============================================================= ' 添加一個(gè)工作表,在該工作表中放置已查找到的單元格地址 ' 如果該工作表存在,則先刪除它 For Each wks In ActiveWorkbook.Worksheets If wks.Name = "查找結(jié)果" Then wks.Delete End If Next wks ' 添加工作表 Sheets.Add ActiveSheet ' 重命名所添加的工作表 ActiveSheet.Name = "查找結(jié)果" ' 在新增工作表中添加標(biāo)題,指明所查找的值 With Cells(1, 1) .Value = "已在下面所列出的位置找到數(shù)值" & szLookupVal .EntireColumn.AutoFit .HorizontalAlignment = xlCenter End With ' ============================================================= ' 定位到剛開始的工作表 ActiveSheet.Next.Select ' ============================================================= ' 提示您是否想高亮顯示已查找到的單元格 If MsgBox("您想加陰影高亮顯示所有查找到的單元格嗎?", vbYesNo, _ "加陰影高亮顯示單元格") = vbNo Then ' 如果不想加陰影顯示單元格,則將變量bTag值設(shè)置為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("查找結(jié)果").Cells(i, 1), "", "'" & wks.Name & "'!" & rCell.Address ' 檢查條件判斷值bTag,以決定是否加亮顯示單元格 Select Case bTag Case True rCell.Interior.ColorIndex = 19 End Select i = i + 1 .StatusBar = "查找到的單元格數(shù)為: " & i - 2 End If Next rCell NoSpecCells: Next wks ' 如果沒有找到匹配的值,則移除新增工作表 If i = 2 Then MsgBox "您所要查找的數(shù)值{" & szLookupVal & "}在這些工作表中沒有發(fā)現(xiàn)", 64, "沒有匹配值" Sheets("查找結(jié)果").Delete End If .Calculation = xlCalculationAutomatic .DisplayAlerts = True .ScreenUpdating = True .StatusBar = Empty End With End Sub
6. 其它一些查找方法
可以使用For Each … Next語句和Like運(yùn)算符進(jìn)行更精確匹配的查找。例如,下列代碼在單元格區(qū)域A1:A10中查找以字符“我”開頭的單元格,并將其背景色變?yōu)榧t色。
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
可以輸入如下圖5所示的數(shù)據(jù)進(jìn)行測試。
7. 擴(kuò)展Find方法
我們能夠使用Find方法查找單元格區(qū)域的數(shù)據(jù),但是沒有一個(gè)方法能夠返回一個(gè)Range對象,該對象引用了含有所查找數(shù)據(jù)的所有單元格,下面提供了一個(gè)
FindAll函數(shù)來實(shí)現(xiàn)此功能。此外,F(xiàn)ind方法的另一個(gè)不足之處是不支持通配符字符串,下面也提供了一個(gè)WildCardMatchCells函
數(shù),返回一個(gè)Range對象,引用了與所提供的通配符字符串相匹配的單元格。通配符字符串可以是有效使用在Like運(yùn)算符中的任何字符串。
7.1 FindAll函數(shù)
這個(gè)程序在參數(shù)SearchRange所代表的區(qū)域中查找所有含有參數(shù)FindWhat代表的值的單元格,SearchRange參數(shù)必須是一個(gè)單獨(dú)的單元格區(qū)域?qū)ο?,F(xiàn)indWhat參數(shù)是想要查找的值,其它參數(shù)是可選的且與Find方法的參數(shù)意思相同。
FindAll函數(shù)的代碼如下:
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區(qū)域中含有FindWhat所代表的值的所有單元格組成的Range對象 ' 其參數(shù)與Find方法的參數(shù)相同 ' 如果沒有找到單元格,將返回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" '要查找的文本,可根據(jù)實(shí)際情況自定 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
上面的代碼中,列出了查找區(qū)域中含有所要查找的數(shù)據(jù)的所有單元格的地址以及相應(yīng)文本。不僅可以找出所有含有所查找數(shù)據(jù)的單元格地址,而且也可以對這些單元格進(jìn)行一系列操作,如格式化、更改數(shù)據(jù)等。
7.2 WildCardMatchCells函數(shù)
這個(gè)程序查找參數(shù)SearchRange所代表的區(qū)域中所有單元格,使用Like運(yùn)算符將它們的值與參數(shù)CompareLikeString所代表的值比
較。參數(shù)SearchRange必須是一個(gè)單獨(dú)的區(qū)域,參數(shù)CompareLikeString是想要比較的文本的格式。該函數(shù)使用單元格的Text屬性
而不是Value屬性。可選參數(shù)SearchOrder和MatchCase與Find方法中的參數(shù)意義相同。
該函數(shù)返回一個(gè)Range對象,該對象包含對與參數(shù)CompareLikeString相匹配的所有單元格的引用。如果沒有匹配的單元格,則返回Nothing。
因?yàn)镕ind方法不支持通配符,程序?qū)⒀h(huán)所有的單元格,因此對于包含大量數(shù)據(jù)的區(qū)域,執(zhí)行時(shí)間可能是一個(gè)問題。并且,如果參數(shù)MatchCase為
False或忽略該參數(shù),文本在程序中必須被轉(zhuǎn)換成大寫,以便于查找時(shí)不區(qū)分大小寫(即“A”=“a”),因此,此時(shí)程序運(yùn)行將更慢。
WildCardMatchCells函數(shù)的代碼如下:
Function WildCardMatchCells(SearchRange As Range, CompareLikeString As String, _ Optional SearchOrder As XlSearchOrder = xlByRows, _ Optional MatchCase As Boolean = False) As Range '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' 本程序返回文本值與通配符字符串相匹配的單元格引用 ' 返回SearchRange區(qū)域中所有相匹配的單元格 ' 匹配的條件是參數(shù)CompareLikeString ' 使用了VBA中的LIKE運(yùn)算符 ' 如果沒有相匹配的單元格或指定了一個(gè)無效的參數(shù),則返回Nothing. ' ' 參數(shù)SearchOrder指定查找的方向;逐行還是逐列(SearchOrder:=xlByRows或SearchOrder:=xlByColumns ' 參數(shù)MatchCase指定是否區(qū)分大小寫(MatchCase:=True, "A" <> "a")或(MatchCase:=False,"A" = "a"). ' ' 不需要在模塊頂指定"Option Compare Text",如果指定的話,將不會(huì)正確執(zhí)行大小寫比較 ' ' 執(zhí)行單元格中的Text屬性比較,而不是Value屬性比較 ' 因此,僅比較顯示在屏幕中的文本,而不是隱藏在單元格中具體的值 ' ' 如果參數(shù)SearchRange是nothing或多個(gè)區(qū)域,則返回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 ' 確保參數(shù)SearchRange不是Nothing且是一個(gè)單獨(dú)的區(qū)域 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 ''''''''''''''''''''''''''''''''''' '如果參數(shù)MatchCase是False,則將字符串轉(zhuǎn)換成大寫 '執(zhí)行忽略大小寫的比較 '因此,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為真,不需要再進(jìn)行大小寫轉(zhuǎn)換,因此更快些 ' 這也是不需要在模塊中指定"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
這樣,在找到所需單元格后,就可以對這些單元格進(jìn)行操作了。