程式化的 Word 文字搜尋與取代
由 darkranger 在 週六, 09/19/2015 - 12:11 發表,更新日期:週六, 01/06/2018 - 17:09
最近在工作上會很需要經常使用 MS Word,對多份稿件進行大量的文字搜尋及取代。雖然早先已寫了一支 Python 程式來處裡,然而在後續檢查內容的過程裡,卻發現原先撰寫的取代功能處理得未盡確實,例如文字方塊(textbox)裡的內容就無法被取代掉。經過上網搜尋後找到了一項解法,儘管確實可行,不過 DR 仍覺得其背後的設計邏輯還蠻弔詭的。
原本的寫法是像這樣:
word.Selection.Find.Execute(FindText="Jack", ReplaceWith="Stanley", Replace=win32com.client.constants.wdReplaceAll, MatchCase=True, MatchWildcards=False)
在 DR 的期望裡,Word 若在未指定任何範圍的情況下,應該要能夠做到全域的搜尋與取代。然而實際的執行結果並非如此,如前所述,例如文字方塊裡的內容就無法被取代到。而解決方案則是改從文件中的本文範圍(StoryRanges)著手,不過其弔詭之處就在於:這項作法的搜尋方法(Find.Execute)必須要用兩次,才能夠順利取代所有本文範圍中的內容。
以下是完整的範例程式碼(word_replace_all.py),該程式會開啟程式所在目錄中的「test.docx」文件,然後搜尋所有的「Jack」字串並取代為「Stanley」:
# -*- coding: utf-8 -*- import os, sys import win32com.client from win32com.client import constants def area_replace(area, find_text, replace_text): area.Find.Execute(FindText=find_text, ReplaceWith=replace_text, Replace=constants.wdReplaceAll, MatchCase=True, MatchWildcards=False) def word_replace_all(): local_encoding = sys.getfilesystemencoding() appdir = os.path.abspath(os.path.dirname(sys.argv[0])).decode(local_encoding) os.chdir(appdir) filename = "test.docx" find_text = "Jack" replace_text = "Stanley" word = win32com.client.gencache.EnsureDispatch("Word.Application") word.Visible = False word.Documents.Open(os.path.abspath(filename)) for story in word.ActiveDocument.StoryRanges: area_replace(story, find_text, replace_text) while(True): if story.NextStoryRange: story = story.NextStoryRange area_replace(story, find_text, replace_text) else: break word.ActiveDocument.Save() word.ActiveDocument.Close(False) word.Quit() if __name__ == "__main__": word_replace_all()
為了突顯重點,上述的範例程式碼並不包含一些實務上會很需要的功能,例如一一開啟目錄中所有的 Word 文件,以及字串取代清單的讀取與套用。除了一般的內文以外,上述程式碼可以處理的區塊包含了文字方塊、註腳(footnote)、文字藝術師(WordArt)以及頁首頁尾(header & footer)。