HI,大家好,我是星光。這章繼續(xù)給大家分享VBA常用對象之單元格的編程技巧。雖然沒有自古以來,但依然眾所周知的是,在Excel中有一個很常用的功能:查找與替換。而在VBA編程中也有與之對應的兩個方法:Find和Replace。 我們先來聊Find,相比于Replace它更常用。
1 丨
基本語法 Find是單元格對象的方法,默認在指定的區(qū)域中查找包含某個數(shù)據(jù)的單元格。若找到符合條件的數(shù)據(jù),則返回包含該數(shù)據(jù)的單元格;若未找到符合條件的,則返回Nothing。 語法格式如下▼
<單元格對象>.Find (What,[After],[LookIn],[LookAt],[SearchOrder],[SearchDirection],[MatchCase],[MatchByte],[SearchFormat]) 語法看的一臉懵逼?都是洋文惹的鍋!其實,以上參數(shù)基本對應了查找對話框中的各個選項。
我來給您翻譯一下:
<單元格對象>.Find (查找值,[查找開始位置],[查找范圍的類型],[匹配方式完全匹配還是部分匹配],[查找方式行或列],[查找方向前或后],[是否區(qū)分大小寫],[全角或半角],[查找單元格的格式]) 還是一臉懵?打個響指,語法中帶中括號的部分都是可選的,所以我再給你簡化一下,只保留最常用的兩個參數(shù)。
<單元格對象>.Find (查找值,[匹配方式是完全匹配還是部分匹配])
這樣是不是就很簡單了?
送佛送到西,不論男女,都抱你上花轎,我再給你舉個例子。
以上圖所示的數(shù)據(jù)表為例,查找是否存在字段名'語文'。如果存在,則彈窗顯示行號和列標;如果不存在,則顯示查無此貨。
示例代碼如下:
代碼看不全可以左右拖動..▼ Sub rngFind() Dim rng As Range '定義一個單元格對象 Set rng = Cells.Find(what:='語文', lookat:=xlWhole) If rng Is Nothing Then MsgBox '查無此貨' Else MsgBox '行:' & rng.Row & ' 列:' & rng.Column End If End Sub
代碼解析▼
第2行代碼定義一個變量rng,類型為單元格對象。
第3行代碼使用Find方法在當前工作表整個區(qū)域中查找字符串'語文',匹配方式為整體匹配(xlWhole),并將查詢結(jié)果賦值給變量rng。
第4行至第8行代碼判斷rng是否為Nothing。如果條件成立,則說明查無結(jié)果;如果條件不成立,則返回查找結(jié)果的行號和列標。
本例返回結(jié)果如下:
2 丨
模糊匹配查詢
Find方法和Excel「查找替換」一樣,也支持模糊匹配。實現(xiàn)的方式有兩種,將匹配方式lookat設置為xlPart,或者在查找值使用通配符。
依然以上節(jié)所示的數(shù)據(jù)表為例,如需查找人名中包含'星光'的語文成績,可以使用以下代碼。
代碼1,xlPart方法..▼Sub rngFindPart() Dim rng As Range '定義一個單元格對象 Set rng = Cells.Find(what:='星光', lookat:=xlPart) '部分匹配 If rng Is Nothing Then '如果查無結(jié)果... MsgBox '查無此貨' Else '如果查有結(jié)果,則向右偏移1位取值 MsgBox rng.Value & '語文成績是:' & _ rng.Offset(0, 1).Value End If End Sub
第3行代碼設置匹配方式為部分匹配,如果查有結(jié)果,第7行代碼使用Offset語句,將結(jié)果單元格向右偏移一個單元格獲取語文成績。
代碼運行后,返回結(jié)果如下:
代碼2,通配符方法..▼
Sub rngFindWildcard() Dim rng As Range '定義一個單元格對象 Set rng = Cells.Find(what:='*星光*', lookat:=xlWhole) '查找值使用了通配符* If rng Is Nothing Then MsgBox '查無此貨' Else MsgBox rng.Value & '語文成績是:' & _ rng.Offset(0, 1).Value End If End Sub
第3行代碼將Find語句的查找值設置為*星光*,星號作為通配符,可以代表任意個字符,因此該查找值的意思就是包含星光的字符串。
……
相比于xlPart方法,通配符要更靈活一些,它不但能表達包含關(guān)系,也能表達以某個字符開始或結(jié)束的查找值,比如看見*,表達了以看見兩個字為開頭的數(shù)據(jù)。*星光,則表達了以星光兩個字結(jié)束的數(shù)據(jù)。
除此之外,還有一個通配符問號?,一個問號只代表一個字符。比如,如果我們需要查找由4個字符構(gòu)成的數(shù)據(jù),查找值可以設置為???? 3 丨
查找工作表
最后數(shù)據(jù)所在的行號
在本系列教程第20課「什么是單元格對象」,咱們分享了多種表達數(shù)據(jù)列表最后一行的方法,如下▼
Sub LastRow() Debug.Print ActiveSheet.UsedRange.Rows.Count Debug.Print Range('a1').CurrentRegion.Rows.Count Debug.Print Cells(Rows.Count, 'a').End(xlUp).Row End Sub
當時也有給大家講了這3種方法各自的優(yōu)缺點;一個糟糕的情況是:在沒有特殊設置的前提下,它們都不能準確的表達數(shù)據(jù)列表最后一行的位置。 以上圖所示的數(shù)據(jù)為例,數(shù)據(jù)的最后一行行號應為10;但以上代碼返回的結(jié)果分別為13(UsedRange)、8(CurrentRegion)、8(End)。至于原因,那一章咱們講過了,這里就不再重復。
使用Find方法可以解決這個問題。代碼如下▼
Sub FindLastRow() Dim rng As Range Set rng = Cells.Find('*', _ LookIn:=xlFormulas, SearchOrder:=xlByRows, _ SearchDirection:=xlPrevious) If rng Is Nothing Then MsgBox '空表,無數(shù)據(jù)' Else MsgBox '最后一行是:' & rng.EntireRow.Row End If End Sub
第3行代碼設置查找值為通配符為*,代表任意字符;查找范圍的類型為公式,查找方式為行,查找方向是向前。運行以上代碼返回結(jié)果如下。
上述Find語句的參數(shù)設置的有點繁多?攤手,確實如此,不過大部分情況下,除了查找值以外,其它參數(shù)都是默認值,是可以省略的。
只所以說大部分情況下是因為……Find語句實際上調(diào)用的是「查找替換」功能的相關(guān)選項設置作為默認參數(shù)的。換句話說,如果用戶使用過「查找替換」功能,并修改了選項設置,比如將查找查找范圍的類型修改為'批注';那么Find方法也就默認使用「查找替換」的屬性,只會在'批注'中查找是否有符合結(jié)果的數(shù)據(jù)。 所以,萬全之策,還是建議在使用Find語句時將相關(guān)參數(shù)設置完整……這可以通過錄制宏來獲取,并不需要強行記憶。
「查找替換」功能的選項設置會影響Find方法,反過來,F(xiàn)ind方法也會影響「查找替換」功能的選項設置。比如,我們使用Find語句設置了查找值、匹配方式等,當你再次打開Excel的「查找替換」功能,就會發(fā)現(xiàn)相關(guān)選項也被修改了。
你可以像我一樣帥不自知,但不能像我一樣掉坑而不自知;所以,以上,多少還是需要留意一下滴。
看個廣告休息一下 沒有廣告的微信文是不真誠的▼
4 丨
查找符合條件的全部結(jié)果
咱們上面講的都是查找一個結(jié)果的情況,如果需要查找的結(jié)果有多個,也就是通常說的一對多查詢,又該怎么處理呢?Find方法并不擁有「查找與替換」功能里【查找全部】的能力——可以使用FindNext語句。
我舉個例子。
如上圖所示,是一張長相喜人的成績表,名稱為'綜合成績表',現(xiàn)在需要查詢'看見星光'所有的考試成績明細,查詢結(jié)果如下。
示例代碼如下:
代碼看不全可以左右拖動..▼ Sub DoFindNext() Dim sht As Worksheet, rng As Range Dim k As Long, strADS As String, s As String Application.ScreenUpdating = False '取消屏幕刷新 ActiveSheet.UsedRange.Offset(1).ClearContents '保留結(jié)果表標題行,清空其它值 s = '看見星光' '查找值 k = 1 '記錄行位置初始為1 Set sht = Worksheets('綜合成績表') '數(shù)據(jù)表 Set rng = sht.Cells.Find(what:=s, lookat:=xlWhole) '完全匹配查詢 If Not rng Is Nothing Then strADS = rng.Address '如果查有結(jié)果,則將單元格地址復制變量strADS Do k = k + 1 '計數(shù)器 Cells(k, 1) = rng '姓名 Cells(k, 2) = rng.Offset(0, 1) '語文 Cells(k, 3) = rng.Offset(0, 2) '英語 Set rng = sht.Cells.FindNext(rng) '查找下一個 If rng.Address = strADS Then Exit Do '循環(huán)一輪后退出Do循環(huán)體 Loop End If Application.ScreenUpdating = True MsgBox '查詢OK' End Sub
代碼解析:
第4行代碼清空當前工作表除了標題行以外的所有數(shù)據(jù)。
第9行代碼使用單元格對象的Find方法,采用完全匹配的方式,在工作表'綜合成績表'中查詢'看見星光'。如果查有結(jié)果,則在第11行代碼返回結(jié)果單元格的地址,并賦值給字符串變量strADS.
第13至第16行代碼累計結(jié)果行數(shù),并根據(jù)查詢結(jié)果單元格的位置,向右偏移,獲取語文和數(shù)學成績等信息,寫入結(jié)果工作表。
第17行代碼使用FindNext語句查詢下一個目標。
FindNext語句的意思是查找下一個目標,語法格式如下。
它只有一個參數(shù),一個指定的單元格,系統(tǒng)將從該單元格之后開始進行查找。既然是之后,那么開始查找時,查找的范圍就不包含該單元格,只有當循環(huán)查了一圈,只剩下該單元格了,才會查找它的內(nèi)容是否符合條件。
根據(jù)這個規(guī)則,我們將首個查詢結(jié)果的地址賦值給變量strADS,然后只要判斷FindNext的返回結(jié)果是否等于strADS,即可判斷系統(tǒng)是否對所有的單元格都查詢過了。如果這個條件成立,則退出Do循環(huán)。
需要注意的是,由于FindNext始終是在指定單元格之后的范圍進行查找,所以必須使用上一次所找到結(jié)果的單元格作為參數(shù),如果使用一個固定的單元格地址,也就會始終返回一個固定的結(jié)果——此時,叮咚,恭喜你,很可能這是你VBA編程生涯第一次陷入死循環(huán)。
……
是不是覺得FindNext很繞?不大好理解?叮咚,再次恭喜你,其實這語句實際上很少用,驚不驚喜意不意外?——同樣的問題,我們更多的時候是使用數(shù)組循環(huán)。
數(shù)組循環(huán)解法如下。
Sub DoArray() Dim s As String, k As Long Dim arr, i As Long, j As Long Application.ScreenUpdating = False '取消屏幕刷新 ActiveSheet.UsedRange.Offset(1).ClearContents '保留結(jié)果表標題行,清空其它值 s = '看見星光' '查找值 k = 1 '記錄行位置初始為1 arr = Worksheets('綜合成績表').UsedRange For i = 1 To UBound(arr)'遍歷行 For j = 1 To UBound(arr, 2) '遍歷列,也就是遍歷數(shù)組中每一個元素 If arr(i, j) = s Then k = k + 1 '計數(shù)器 Cells(k, 1) = s '姓名 Cells(k, 2) = arr(i, j + 1) '語文成績 Cells(k, 3) = arr(i, j + 2) '數(shù)學成績 End If Next Next Application.ScreenUpdating = True MsgBox '查詢OK' End Sub
第9行至第18行代碼遍歷數(shù)組中的每一個元素,如果元素等于查找值,則按列偏移獲取語文和數(shù)學的成績——這思路是不是比FindNext語句簡單多了?簡直是數(shù)組無腦循環(huán)的典范!
有位叫李宗盛的大哥說過,有一天,你會知道,在VBA編程里無腦循環(huán)并不是貶義詞~……
……
5 丨
Replace語句
最后再給大家講一下如何用VBA代碼實現(xiàn)「替換」功能,也就是單元格Replace方法。語法格式如下▼
<單元格對象>.Replace(What、Replacement、LookAt、SearchOrder、MatchCase、MatchByte、SearchFormat、ReplaceFormat)
<單元格對象>.Replace(查找值、替換值、匹配方式是完全匹配還是部分匹配、[查找方式行或列]、是否區(qū)分大小寫、全角或半角、按格式搜索、按格式替換) 最常用的只有前面3個參數(shù),簡化后如下。
<單元格對象>.Replace(查找值,替換值,匹配方式:完全匹配還是部分匹配) 舉個例子,將當前工作表中所有的'看見星光'替換為'看見月光'。
代碼如下▼
Sub rngReplace() Cells.Replace '看見星光', '看見月光', xlWhole End Sub
是不是很簡單?
需要注意的是,和Find方法一樣,「查找替換」的選項設置也會影響Replace方法,反過來,Replace方法也會影響「查找替換」相關(guān)選項設置。比如,以上述代碼為例,如果省略了第3參數(shù),則通常默認執(zhí)行的是部分匹配,畢竟部分匹配是「查找替換」的默認選項。
……
就醬,打完手工,下期再見。
|