連代碼調試都一竅不通,還談啥會VBA?

      網友投稿 587 2025-04-02

      連代碼調試都一竅不通,還談啥會VBA?


      有句俗話說的好,一段優秀的代碼,三分靠編寫七分靠調試。今天我就給大家聊一下VBA代碼調試的問題:一段代碼寫完了,運算結果卻不對,到底應該如何發現并改正錯誤?

      本章概要如下:

      ? 語法檢查? 邏輯檢查? 樣本調式? 運行調試? 錯誤處理

      1、語法錯誤

      對于新手而言,初期編寫的VBA代碼并不會有復雜的邏輯,最常見的錯誤就是語法錯誤。典型有以下3種。

      以上代碼第3行將第1個工作表賦值變量sht,但由于并未使用關鍵字Set,代碼會返回下圖所示的錯誤信息:對象變量或with塊變量未設置。

      正確代碼如下:

      Sub t()Dim sht As WorksheetSet sht = Worksheets(1)MsgBox sht.NameEnd Sub

      2)循環或判斷語句不完整。

      當有多層循環語句或者條件判斷語句嵌套時,新手朋友容易遺漏Next或者End If語句。需要注意的是,當If語句嵌套在循環語句中時,如果缺少End If,系統會提示”編譯錯誤,Next沒有For”。這提示張冠李戴的不要太明顯。

      以下代碼缺失End If語句。

      Sub t3()Dim sht As WorksheetFor Each sht In WorksheetsIf sht.Name = "看見星光" ThenIf sht.Cells(1, 1) = "excel" ThenMsgBox "對"'這里少了End If 你發現了嗎?NextEnd Sub

      運行后提示錯誤如下:

      解決此類錯誤,最好是養成代碼縮進與提前輸入結構語句的習慣。關于代碼縮進的規則,VBA系列教程里有詳細的講述,這里不再啰嗦。而輸入結構語句是指…寫了For語句后,立刻空兩行寫Next語句,再在循環體中編寫其它語句。For Each sht In Worksheets

      Next寫了If語句后,也空兩行寫End If語句。If sht.Name = "看見星光" Then

      End If

      3)工作表對象缺失

      這個錯誤基本上每個VBA學員都遇見。有段代碼如下:代碼看不全可以左右滑動…

      連代碼調試都一竅不通,還談啥會VBA?

      Sub t4()Dim arrarr = Worksheets(1).Range("a1:b" & Cells(Rows.Count, 1).End(xlUp).Row)End Sub

      第3行代碼將第1個工作表的A:B列數據區域賦值數組arr。其中Cells(Rows.Count, 1).End(xlUp).Row部分,本意是返回Worksheets(1)第1列最后一個存在數據的單元格的行號,這代碼看起來似乎正常無誤。但是,我們在VBA教程里講過,如果單元格前未指定工作表對象,則默認為當前活動工作表——當前活動工作表,未必就是Worksheets(1),代碼運行后,arr數組也就未必會返回正確的結果。

      正確代碼參考如下:

      Sub t4()Dim arrWith Worksheets(1)arr = .Range("a1:b" & .Cells(Rows.Count, 1).End(xlUp).Row)End WithEnd Sub

      注意Cells前有個.代表With所引用的Worksheets(1)對象。

      2、邏輯錯誤

      相比于語法錯誤,麻煩的是邏輯錯誤。代碼運算的邏輯,有些來源于數據分析與處理的基本邏輯,有些來源于公司的業務邏輯。對于后者,往往只有行業內的人才能通過你的描述快速理解。這時就有可能發生這樣的情景:有的朋友發出來一段代碼,也不說運算邏輯,就問為什么代碼運行后不提示錯誤,但結果并不對……坦白的說,這種行為就給有人問為什么輸入公式1+1不提示錯誤,但結果也不等于預想的3,差不了多少——就讓人很無語。

      如何梳理邏輯錯誤呢?首先,正如我們一直強調的,所謂編程,就是順序、分支和循環。順序就是運算的先后順序,分支就是運算的條件層次,循環就是遍歷數據,所以請養成做思維導圖的習慣,通過思維導圖梳理清楚代碼運算的順序和條件層次——相信我,這非常有助于你快速而準確的編寫代碼。然后,在代碼中盡量增加注釋。注釋的好處我們在VBA系列教程中編寫VBA代碼有哪些注意事項里有詳細解釋,像我這么傲驕的人,這里不再重復,你懂得圖片。

      最后,請繼續往下看(*^▽^*)

      3、樣本調試

      不論是檢查代碼的語法錯誤還是邏輯錯誤,都離不開樣本調試;也就是用一個樣本數據逐步運行代碼,發現并修正錯誤。上面這句話包含了兩個重點詞匯:樣本數據、逐步運行。樣本數據要求小而全。

      小是指數據量必須小,比如,你需要從如上圖所示的10萬行數據中查找A列包含關鍵字”上?!薄ⅰ备=ā?、”廣東”,同時B列性別等于男的結果表,你不能拿10萬個數據一個一個去測試,這樣你不是風兒也是沙;實際上,有3條左右的樣本數據就足夠了。

      全是指數據的代表性需全面,依然以上圖所示數據為例,C列的性別就不能只有男的,沒有女的,當然,也不能只有女的,沒有男的。

      參考代碼如下:

      Sub t()Dim aData, aRes, aRef, sDim i As Long, j As Long, k As LongaData = Worksheets("數據源").Range("a1").CurrentRegionReDim aRes(1 To UBound(aData), 1 To UBound(aData, 2))aRef = Array("上海", "福建", "廣東")For i = 1 To UBound(aData)If aData(i, 3) = "男" Then '判斷性別是否為男For Each s In aRef '判斷是否包含城市關鍵字If InStr(aData(i, 1), s) Thenk = k + 1For j = 1 To UBound(aData, 2)aRes(k, j) = aData(i, j)NextExit For '退出循環End IfNextEnd IfNextWorksheets("結果表").SelectCells.ClearContentsRange("a1").Resize(1, UBound(aData, 2)) = aData '讀取標題Range("a2").Resize(k, UBound(aRes, 2)) = aResMsgBox "ok"End Sub

      4、代碼調試

      重點說一下代碼逐步調試,這包含了逐語句調試、斷點調試等情況。逐語句調試是指以語句為單位分步運行代碼。按一次鍵,VBA將運行當前過程,然后高亮顯示下一個語句并進入中斷模式。按多次鍵,即可逐語句運行代碼。

      當代碼逐語句運行時,我們可以通過本地窗口,實時查看變量內容是否符合計算預期。

      斷點調試就是在程序中設置代碼暫時停止運行的位置,這個位置被稱為斷點。當代碼運行到斷點所在的語句時,程序會進入中斷模式,同時高亮顯示斷點代碼行。設置斷點最常用的方法是將鼠標指針懸停在【代碼窗口】左側灰色區域內,當鼠標指針顯示為指向左上方的箭頭時,單擊即可設置該代碼行為斷點。

      斷點設置完成后,會出現一個紅色大圓點,單擊該斷點標識,即可刪除斷點。斷點可以存在多個,如果存在斷點,按鍵后,VBA將運行代碼直至斷點處進入中斷模式。此時,通過本地窗口,或搭配運行MsgBox語句,可以查看代碼中的變量值是否運行有誤。

      除此之外,使用Stop語句也可以實現斷點調試的效果。以上述代碼為例,如果需要查看變量K的累加過程,可以在語句k=k+1后添加一行Stop語句,代碼運行到Stop語句時將自動進入中斷模式,再通過本地窗口,即可查看相關變量的數據。

      不管是逐語句調試還是斷點調試,都是為了查看代碼的運算過程,以及變量的值是否正確。查看變量優先推薦使用本地窗口,但有時候本地窗口的變量過多,如果只是查看個別變量,使用起來就不是很方便,相比之下,使用Msgbox語句更為合適。以上述案例為例,如果需要查看第1條符合查詢規則的行號,可以在If判斷語句后增加以下兩行代碼。

      …MsgBox iStop….

      代碼運行后返回結果如下圖所示。

      本地窗口和Msgbox語句都是顯示某個運算環境下的特定值,如果需要查看特定變量在整個過程中的全部值,可以使用Debug對象的Print方法,該方法可以在【立即窗口】打印不同類型的數據。還是舉個例子。在第10行If語句后,增加一行Debug.Print (i)語句,然后運行過程,可以在立即窗口查看所有符合條件的所有行號。

      Debug.Print 比較常用的一個情景是測試不同代碼的運行速度。以下代碼測試了將10000個數據寫入工作表的兩種方式的時間差異,這兩種方式一個是逐個單元格寫入,另一個是數組批量寫入。

      Sub t2()Dim i As Long, arr, tt = TimerFor i = 1 To 10000 '在1萬個單元格中寫入數據Cells(i, 1) = iNextDebug.Print ("逐個單元格寫入的時間是:" & Timer - t)t = TimerReDim arr(1 To 10000, 1 To 1)For i = 1 To 10000arr(i, 1) = iNextRange("b1:b" & UBound(arr)) = arrDebug.Print ("數組寫入的時間是:" & Timer - t)End Sub

      運行代碼后結果如下圖所示:

      最后需要補充說明兩點:

      1)當過程重復運行時,立即窗口的內容并不會自動清除。2)除了將變量數據寫入立即窗口,也可以將其寫入工作表中,兩者各有優劣,看個人習慣和實際需求。

      5、錯誤處理

      無論你如何認真的編寫代碼,程序運行時仍然有可能出現錯誤,這也許會讓初學編程的你感到困惑,但從某種角度來說,錯誤確實是程序不可或缺的一部分,所以請躺平微笑面對錯誤,并堅定不移的抱有三種態度:忽視它、捕捉它、反饋它。

      使用On Error Resume Next語句,可以忽視程序中的錯誤,繼續運行錯誤語句后的代碼。

      以下代碼刪除名稱為”數據”的工作表。為了防止工作簿不存在相關名稱的工作表,造成第4行刪除工作表的代碼運行錯誤,第3行代碼使用容錯語句。

      Sub t3()On Error Resume NextApplication.DisplayAlerts = FalseWorksheets("數據").DeleteMsgBox "名稱為數據的工作表已刪除"Application.DisplayAlerts = TrueEnd Sub

      捕捉和反饋錯誤可以使用Err對象。

      舉個例子,還是刪除名稱為”數據”的工作表,示例代碼如下:

      Sub t4()Dim d As ObjectApplication.DisplayAlerts = FalseSet d = CreateObject("scripting.dictionary") '演示釋放變量On Error GoTo ErrHanderWorksheets("數據").DeleteMsgBox "名稱為數據的工作表已刪除"Application.DisplayAlerts = TrueerrExit:Set d = NothingExit SubErrHander:MsgBox "程序發生錯誤。" & vbCrLf & _"錯誤編號:" & Err.Number & vbCrLf & _"錯誤內容:" & Err.DescriptionResume errExitEnd Sub

      第5行代碼是On Error GoTo line語句。它可以跳轉到指定的錯誤處理程序入口,line代表代碼行標簽或行號,本例為ErrHander。

      第12至第16行代碼是ErrHander標簽。第14行代碼使用Err對象的Number屬性返回錯誤的編號,第15行代碼使用Err對象的Description返回錯誤的描述內容(這描述大部分時候不講人話,如下圖所示,就湊合用吧)。

      第9至第11行代碼是errExit標簽,作用是釋放指定對象的內存。使用Err.Number屬性可以判斷程序是否存在錯誤。

      以下代碼刪除名稱為”數據”的工作表。如果不存在相關工作表,則告知用戶。

      Sub t5()On Error Resume NextApplication.DisplayAlerts = FalseWorksheets("數據").DeleteIf Err.Number = 0 ThenMsgBox "名稱為數據的工作表已刪除"ElseMsgBox "不存在名稱為數據的工作表"End IfApplication.DisplayAlerts = TrueEnd Sub

      第5行代碼判斷當前程序是否存在錯誤,當程序不存在錯誤時,Err的Number屬性為0。當程序存在錯誤時,Number屬性可能是正數也可能是負數,有學員將判斷條件寫成Err.Number > 0是錯誤的。

      最后,使用Err.Clear可以清除Err對象的所有屬性,即清除錯誤。

      假設需要刪除工作表名稱為”工作表1″, “工作表2”, “工作表3″,并將刪除的和不存在的分別彈窗告訴用戶,可以參考下代碼遍歷刪除。

      Sub t6()Dim aData, strNameDim strDelName As String, strErrName As StringOn Error Resume NextApplication.DisplayAlerts = FalseaData = Array("工作表1", "工作表2", "工作表3")For Each strName In aDataErr.ClearWorksheets(strName).DeleteIf Err.Number = 0 ThenstrDelName = strDelName & "," & strNameElsestrErrName = strErrName & "," & strNameEnd IfNextMsgBox "以下工作表已刪除:" & vbCrLf & Mid(strDelName, 2) & vbCrLf & _"以下工作表不存在:" & vbCrLf & Mid(strErrName, 2)Application.DisplayAlerts = TrueEnd Sub

      第4行代碼忽視程序運行中的錯誤。

      第8行代碼在每次刪除工作表前都清除Err對象的所有屬性。第10行代碼判斷Err對象的編號是否為0,如果為0,說明工作表成功刪除,否則,就假設工作簿中不存在相關工作表(攤手,是的,事實上,也有可能是工作簿結構被保護了)。

      代碼運行后返回結果如下:

      6、小結

      同志們吶,代碼調試是一個需要保持耐心和細心的過程,這里重復一句話(小學老師說過這叫首尾呼應),一段優秀的代碼三分在編寫七分在調試,寫一段代碼你可能只需要十分鐘,而調試卻需要1小時——這都是很正常的。最后,用大老板的一句話勉勵大家:“唯有不忘初心、牢記使命,戒驕戒躁、砥礪前行,方能行穩致遠?!?/p>

      來源:https://mp.weixin.qq.com/s/YY0_eHG1ppS17AKrlnC7wA

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:excel如何自定義下拉菜單?excel添加自定義下拉列表方法
      下一篇:Excel動態統計及格人數
      相關文章
      亚洲男人在线无码视频| 国产亚洲精品福利在线无卡一| 国产亚洲精品成人a v小说| 久久亚洲欧美国产精品| 亚洲精品国产摄像头| 亚洲最大的成人网| 亚洲乱码一二三四区麻豆| 亚洲啪啪免费视频| 亚洲Av高清一区二区三区| 亚洲1区1区3区4区产品乱码芒果| 亚洲国产成人久久三区| 亚洲av无码久久忘忧草| 亚洲国产综合精品中文第一| 在线综合亚洲欧洲综合网站| 亚洲粉嫩美白在线| 亚洲色成人WWW永久在线观看| 中文字幕亚洲精品无码| 亚洲av无码一区二区三区人妖| 亚洲av中文无码字幕色不卡| 夜色阁亚洲一区二区三区| 亚洲av无码乱码在线观看野外 | 亚洲av无码av在线播放| 亚洲精品动漫免费二区| 国产精品亚洲lv粉色| 免费在线观看亚洲| 亚洲乱码日产精品a级毛片久久| 亚洲人妻av伦理| 亚洲精品无码不卡在线播HE| 亚洲va中文字幕无码久久不卡| 日韩精品亚洲人成在线观看| 亚洲伊人色一综合网| 亚洲精品美女久久7777777 | 亚洲.国产.欧美一区二区三区| 亚洲国产成人VA在线观看| 亚洲精品无码99在线观看 | 亚洲国产成人片在线观看无码| 91在线亚洲精品专区| 亚洲不卡在线观看| 国产亚洲一卡2卡3卡4卡新区| 亚洲精品人成无码中文毛片| 亚洲国产AV无码专区亚洲AV|