Office Space:撰寫 Microsoft Office 應用程式指令碼的秘訣

Office Space

歡迎蒞臨 Office Space 專欄,這裡提供處理 Microsoft® Office 應用程式指令碼的秘訣。每週二和週四我們將刊出新的秘訣,若要參閱以前討論過的秘訣,請造訪 Office Space Archive (Office Space 過往文件)。您有關於系統管理指令碼方面的問題嗎?請將電子郵件傳送到 scripter@microsoft.com。我們無法保證能夠逐一回答每個問題,不過我們會盡力而為。

尋找及取代 Microsoft Word 文件的文字

改變是不可避免的,但並不表示改變總是好的。比方說您在 Contoso 工作,對了,您認識一個叫 Ken Myer 的人嗎?他也在 Contoso 做過,個子高高的,帶點紅髮?

言歸正傳,您在 Contoso 上班,有一天早上進辦公室的時候發現公司名字竟然改成了 Fabrikam (嘿,哪家公司不會想把名字改成像 Fabrikam 這麼酷的名字呢!)。這倒也還好,問題出在,您有一大堆 Word 文件,像是範本、訓練教材、表格書信之類的,都是使用舊的公司名稱:Contoso。結果您現在必須打開每份文件,把 Contoso 都改成 Fabrikam。真是天呀…

在 Microsoft Word 中尋找和取代文字是不怎麼難沒錯,大多數人也都很熟悉 [尋找及取代] 對話方塊:

尋找及取代


唯一的問題是您必須把 Word 文件一份一份打開,手動帶出 [尋找及取代] 對話方塊,鍵入適當的條件,然後按下 [全部取代]。如果只有兩三份文件,那倒沒關係,問題是要是您有兩三百份文件呢?像這樣的工作可能會花上好一段時間。我們可以透過程式設計的方法來尋找和取代 Word 文件中的文字嗎?這樣的機率您覺得有多大?

不過,Scripting Guy 在 Kentucky Derby 賽馬中押注失算 (沒有人告訴我們 Secretariat 那匹神駒已經死了,更別提它根本沒參加今年的賽馬),現在完全反對賭博和種種類似的墮落行為,所以我們並不知道機率有多大。但是我們可以告訴您,要透過程式設計的方式尋找和取代 Word 文件中的文字很簡單。假設有個簡單的程式碼,可以告訴我們是否能夠在 C:\Scripts\Test.doc 文件中找到「Contoso」一字:


Set objWord = CreateObject("Word.Application")
objWord.Visible = True

Set objDoc = objWord.Documents.Open("C:\Scripts\Test.doc")
Set objSelection = objWord.Selection

objSelection.Find.Text = "Contoso"
objSelection.Find.Forward = TRUE
objSelection.Find.MatchWholeWord = TRUE

If objSelection.Find.Execute Then
    Wscript.Echo "The search text was found."
Else
    Wscript.Echo "The search text was not found."
End If


在這邊要做的呢,是先建立 Microsoft Word (Word.Application 物件) 的執行個體,然後將 Visible 屬性設為 True,設定後者是為了能夠在螢幕上看見文件。接下來使用 Open 方法來開啟 C:\Scripts\Test.doc 文件,文件開啟後,馬上在文件的最開始建立 Selection 物件的執行個體。

有趣的部分來了,結果 Selection 物件有個子物件:Find。正如其名,Find 物件可用來尋找文件中的項目。今天的重點是要尋找文字,不過 Find 物件也可以用來尋找格式、樣式、圖片、特殊字元,以及任何可以使用 [尋找及取代] 對話方塊所找到的項目。那些花俏的東西我們以後再說,現在先來看看找不找得到「Contoso」一字。

Find 物件有三個屬性要設定:

  • Text。這單純只是我們要搜尋的文字,因此將 Text 屬性的值設為「Contoso」。

  • Forward。這是要搜尋的方向,因為 Selection 物件是在文件開頭建立的,所以要往下 (亦即,往文件的結尾) 尋找。因此把 Foward 屬性的值設為 True。

  • MatchWholeWord。這會直接指示指令碼只尋找「Contoso」一字,在本例中,不太可能在其他字裡面找到「Contoso」一字。不過,假設我們是要把「cat」一字以「dog」一字來取代的話,如果找不到完整字,就會以「dog」來取代字母「c-a-t」的例項,換句話說,像「catalog」這類的字最後會被改成「dogalog」。為了防止這種怪事發生,我們將 MatchWholeWord 設為 True。

注意:Find 物件可以設定的屬性還多得很,如需完整清單,請參考 MSDN 上的 Microsoft Word VBA Language Reference (英文)。


設定好 Find 物件的屬性之後,接著呼叫 Execute 方法來搜尋文件。如果找到搜尋文字,Execute 會傳回 True,如果找不到,就傳回 False。我們會查看 Execute 方法傳回的值,然後回報適當的訊息。這個動作是由這段程式碼進行:


If objSelection.Find.Execute Then
    Wscript.Echo "The search text was found."
Else
    Wscript.Echo "The search text was not found."
End If


目前看來都沒問題,這個程式碼會告訴我們是否能在 Test.doc 中找到「Contoso」一字,不過說老實話,這項資訊其實不是那麼重要:如果文件不包含「Contoso」一字,我們也不是很在乎,要是真的有「Contoso」一字,當然是希望將之取代成「Fabrikam」。那麼尋找及取代指令碼的取代部分要怎麼寫呢?

實際上,就像這樣:


Const wdReplaceAll  = 2

Set objWord = CreateObject("Word.Application")
objWord.Visible = True

Set objDoc = objWord.Documents.Open("C:\Scripts\Test.doc")
Set objSelection = objWord.Selection

objSelection.Find.Text = "Contoso"
objSelection.Find.Forward = TRUE
objSelection.Find.MatchWholeWord = TRUE

objSelection.Find.Replacement.Text = "Fabrikam"
objSelection.Find.Execute ,,,,,,,,,,wdReplaceAll


您可以看到這個指令碼的絕大部分跟第一個指令碼非常像,不過第一行是新加的:先是定義一個名為 wdReplaceAll 的常數,並且將值設為 2,之後會使用此文件來告知指令碼自動取代「Consoto」一字的所有例項。接著是開啟 Word 文件,並設定 Find 物件的屬性,使用在指令碼中一模一樣的程式碼來報告文件中是否找得到「Consoto」一字。

兩個指令碼只有在這裡有所差別。因為實際要取代「Contoso」的現有例項,所以需要設定 Replacement 物件 (Find 物件的子物件) 的部分屬性。加上主要的考量是要以一個字直接取代另一個字,因此唯一需要設定的屬性是 Text 屬性,即我們的取代文字。我們想要使用「Fabrikam」作為取代文字,所以設定 Text 屬性的程式碼看起來像: objSelection.Find.Replacement.Text = "Fabrikam"

接著是呼叫 Execute 方法,不過這次的程式碼看起來有點古怪:


objSelection.Find.Execute ,,,,,,,,,,wdReplaceAll


這麼多逗號是要做什麼?首先呢,Execute 方法有一大堆選用參數 (如需完整清單,請參閱 Word VBA Language Reference(英文),在第一個指令碼中 (就是只搜尋文字的那個),並不需要任何選用參數,所以我們不加任何參數呼叫 Execute 方法。不過,若要取代文字,就必須指明我們想要自動取代「Contoso」的所有例項,所以在參數清單中才會有 wdReplaceAll 常數。

那逗號是何用途?如果要指明我們想要取代「Contoso」一字的所有例項,wdReplaceAll 常數必須是參數清單中的第十一個項目,也就是說它前面必須有其他 10 個參數。雖然不想要設定任何參數,但還是得指明它們的存在,所以就使用空白參數,並以逗號來分隔。看起來雖蠢,可是有效:只要執行指令碼,就會看到「Contoso」的每個例項都會被「Fabrikam」一字所取代。

雖然我們仍然不確定改變是不是好事,不過只要因應變化都這麼簡單的話,誰管它呢?加上指令碼確實使得取代 Word 文件中的文字是既迅速又容易,讓我們有充足的時間從事其他活動 (不要說出去,我們聽說下一場賽馬看好 Man o'War)。

顯示: