雜談:從不懂到改寫別人的VBA不難,但對心臟不太好 / TALK: From Novice to VBA Rewriter: An Easy but Stressful Journey
最近幫別人改寫老舊Excel上的VBA,讓使用者能直接從輸入資料到彙整成可以列印的格式,而避免大量的複製、貼上操作。寫是寫完了,但內心真是五味雜陳。
不是每個Excel版本都能順利執行VBA / Not Every Excel Version Can Run VBA Smoothly
前情提要一下。目前在單位裡面使用的Excel以及裡面的VBA,並不是像你各位用的華麗Office 365的版本 (還可以跑Python in Excel!),而是老舊的「.xls」格式。
是的,即使是到了2025年,大部分非資訊人員的單位仍會保持著「能跑就好」的心態,在特定電腦上運作特定版本的Office,以及使用特定版本Excel檔案裡面的VBA。
這點對我這個Linux的使用者來說似乎有點棘手。但其實我早在VirtualBox裡面常備了幾個Windows版本,除了為了運作特定只能在Windows下執行的軟體之外,也是為了在製作教學的時候配合一下Windows的環境。
不過實際上把Excel放到虛擬機器裡面之後,我發現事情不太妙。新版本的Excel執行這個舊版.xls檔案裡的VBA錯誤百出。這似乎是Excel安全性層級的問題,但我有點摸不著頭緒。預設我逐漸將Excel的版本一路往下降,降到Excel 2003,並降低了安全性層級,這才讓.xls的VBA能夠正常運作。
嘗試到一半的時候,我曾經詢問檔案擁有者他使用的Windows作業系統跟Excel版本,但對方似乎無法理解Excel的「版本」差異。其實大部分的使用者都是如此,公司給你這臺電腦、裝著這個版本的Excel,員工用就是了,不會在意什麼版本問題。
亂碼問題 / Garbled Characters
然而版本的問題還不只是Excel本身,另一個問題是我使用的Windows版本。由於我長年使用Linux的緣故,通常系統語言我預設都會選用英文,以減少中文亂碼的問題。但這次在修改Excel時,工作表的中文雖然可以正常顯示,但是在VBA裡面卻全部變成了亂碼。
https://home.gamer.com.tw/creationDetail.php?sn=3286189
造成亂碼的原因是因為英文版的Windows預設在處理非Unicode的文字時使用的還是英文,把它改成「中文(繁體,臺灣)」之後,VBA裡面原本是「?」的文字就會顯示成中文了。
然而這也只是「顯示」而已。如果我將含有中文的文字貼到VBA裡面,它依然會變成亂碼。
後來我的解法是:
- 複製含有中文的文字。
- 貼上到Excel工作表的欄位裡。
- 複製工作表裡面的值。
- 貼上到VBA。
這樣就可以避開亂碼的問題。
但我認為更好的做法是:從一開始就不要寫中文,都用英文來寫。這樣應該是根絕亂碼問題的最佳做法。
AI能夠幫忙寫VBA嗎? / Can AI Help Write VBA?
很多人都聽聞了現在AI寫程式非常厲害,交給AI就行了。
但根據這次的經驗,我發現AI有沒有能力寫程式並不重要,重要的是如何將委託任務轉換成程式可以解決的形式。比較直白地來講,那就是要搞懂委託人到底要作什麼。
沒錯,就如大多數一般人一樣,委託人說著「這個很簡單啦,你就叫程式這樣這樣、那樣那樣」,但背後的邏輯跟規則卻有十幾種變化。要嘛是委託人目前只會做到當下的工作,沒有意識到下次要再做同樣的任務時,Excel裡面的資料已經完全變了個樣;要嘛是委託人憑藉著天才般的直覺和靈敏的反應,自動忽視並克服了資料之間的細微變化,但實際上資料狀況卻是有很大的差異。
在初步和委託人談完需求後,後來我在分析資料結構上花的時間反而更多。在瞭解要輸入的資料,以及輸出的資料可能的形式之後,中間的資料處理的確可以請AI代寫...
...嗎?當然不是。
我只是請Gemini幫我寫一個列印時重複標頭的功能,不知為何VBA裡面出現了俄文「повторяющиесястроки」。另一方面,ChatGPT雖然能寫出看起來似乎合理的程式碼,但偶爾運作起來還是會發現不少邏輯上的錯誤。需要我們一一手動修正。
VBA的限制 / Limitations of VBA
就算用ChatGPT或Gemini來寫VBA,寫出來的程式碼還是非常複雜。然而這個複雜的原因,很大一部分在於VBA程式語言並沒有像現代程式語言JavaScript、Python這樣的靈活。
舉個例子來說:VBA的迴圈沒有Continue的功能。根據Jean-François Corbett的建議,我們必須用If來替代。
另一個例子是VBA的子程序沒有回傳值(return)的功能。但VBA子程序傳遞的參數是用傳址的形式進行,這導致子程式裡面修改的變數會影響到子程序之外。這雖然是實作回傳值的做法,但跟現在的程式語言真的是差的很多,第一次遇到的時候我真的是嚇個半死。詳細的概念請看G. T. Wang寫的「Excel VBA 程式設計教學:函數(Function)與子程序(Sub)」。
https://zanzan.tw/archives/34558
還有另一個讓我覺得非常困擾的限制就是VBA的陣列形態。VBA的陣列必須在一開始就宣告它的長度以及資料類型,但這對資料處理來說實在是很大的限制。通常我們要塞在陣列裡面的資料類型各異,長度也不容易預先預測。一般程式語言我們大多都會用動態陣列來實作,就算是Java也還有ArrayList可以用。至於VBA,它的確還有ReDim跟Preserve這些進階語法可以達到動態陣列的效果,但寫起來就會讓程式變得很複雜。
仍然無法放棄使用VBA / Still Unable to Give Up Using VBA
也許有很多程式設計師看到VBA這麼難寫,就會紛紛主張說什麼要用 Python啦、Rust啦、Node.js之類的來改寫。
然而,以我對現場的瞭解來說,其實Excel的VBA還真的有其難以替代的價值。
首先,只要在設定好的環境裡,我們可以將表格資料與VBA程式碼統一封裝在一份xls檔案裡面。這使得VBA的佈署和使用門檻降到極低的程度。你看看Python使用者還在那邊用pipx安裝相依套件(然後還會遇到x86/ARM的相容性問題),Excel使用者打開檔案就可以按按鈕執行VBA了。
另一方面是Excel在輸出成列印文件時仍有極大的優勢。文件的列印其實一直都是Office套件的強項。在設定好的環境裡,使用者總是能夠將列印文件調整到最完美的程度,而這點也是Excel VBA的特殊長才。相較之下,合併列印僅能處理單純的資料、網頁的CSS列印功能只能說是聊勝於無。後來有不少人提倡以文件範本搭配資料變數來產生可列印文件,例如「docx-template-to-pdf-microservice-js」,但實際上用起來要嘛版面超過一頁、要嘛就是資料超出範本欄位。
如果是要以列印紙本作為最終目標,那Excel VBA的重要性我想應該還是可以繼續維持。但如果是在數位環境下閱讀資料的話,就沒有必要在Excel裡面追求完美的排版了。因此可以的話,還是盡量朝向數位化邁進吧。
改寫VBA的經驗 / Experience Rewriting VBA
最後來講講我改寫VBA的經驗。
我會寫VBA嗎?嚴格來說,我並沒有上過什麼關於VBA的課程。就跟我所會的大多數技能一樣,VBA也是自學的。
上次修改VBA是在當兵期間。當時為了改善讓製作值班表的過程,我直接看Microsoft Visual Basic說明來寫VBA。軍中的環境並沒有網際網路,我擁有的參考資源就只有Excel內建的說明。是說我從很久以前就是用看文件來學寫軟體,而這些文件大多時候按F1就可以叫出來。後來我才發現原來幾乎所有人都不知道F1可以叫出說明。
當時寫完之後立刻就忘記VBA的寫法了,這次再逢VBA大概已經過了10年。這次有了網際網路跟AI的輔助,寫起來雖然遭遇了很多問題,但其實也稱不上什麼難關,大概也是嘗試個一兩次改寫就可以克服的程度。
儘管如此,我想下次再碰到VBA的時候,我應該還是無法直接寫出動態陣列這麼複雜的玩意兒吧。
https://tbtech.co/news/node-js-vs-python-key-differences/
我還是回來寫Node.js跟Python好了,它們可愛多了。