前兩天有個朋友向我求助,她在寫畢業論文時,不小心將論文裡的中文雙引號替換為英文的了,各種原因導致無法回退,8萬多字的論文,眼看就要交了,該怎麼辦?
首先想到 word 自身的替換功能,倒是能查到,但是沒法動態替換,即只替換兩邊引號,而不換中間內容;
另外一種方案是,即用 VBA,通過編程來替換,雖說做過幾個項目,可好久不用,拾起費勁,再加上 VBA 中各種概念和用法,學習成本太高,放棄;
還有一種方案,即用 Python 操作 word,首先對 Python 更熟悉,另外一定有別人造好的輪子。果然,沒用多久找到了 python-docx Python 庫,文檔齊全,功能強大,用來解決替換問題不在話下。
開始之前,先簡單了解下 python-docx
python-docx 介紹python-docx 是用於創建可修改 微軟 Word 的一個 python 庫,提供全套的 Word 操作,是最常用的 Word 工具
概念使用前,先了解幾個概念:
Document:是一個 Word 文檔 對象,不同於 VBA 中 Worksheet 的概念,Document 是獨立的,打開不同的 Word 文檔,就會有不同的 Document 對象,相互之間沒有影響Paragraph:是段落,一個 Word 文檔由多個段落組成,當在文檔中輸入一個回車鍵,就會成為新的段落,輸入 shift + 回車,不會分段Run 表示一個節段,每個段落由多個 節段 組成,一個段落中具有相同樣式的連續文本,組成一個節段,所以一個 段落 對象有個 Run 列表例如有一個 Word,內容是:
word 文檔內容則 結構這樣劃分:
第二個 段落(paragraph),沒有內容,所以 節段(run)為空
安裝可以用 pip 來安裝:
命令行中運行下面語句,如果沒有報錯,則說明安裝成功
$ python -c 'import docx'小試牛刀python-docx 安裝後,測試一下:
from docx import Document
document = Document()paragraph = document.add_paragraph('Lorem ipsum dolor sit amet.')prior_paragraph = paragraph.insert_paragraph_before('Lorem ipsum')
document.save(r"D:\test.docx")再在這個段落(paragraph)前插入另一個段落最後調用文檔對象 document 的 save 保存文檔用 Word 打開保存的 test.docx 就可以看到:
問題分析與解決了解了 python-docx 的基本概念,開始著手解決問題,大體思路是:
將找到的內容的 英文引號 換成 中文引號,並將內容替換回去查找目標首先要解決的是如何找到 英文引號之間的內容?
例如文檔內容有這麼一段:
...對"基於需求的教育資源配置系統觀"的研究,尤其是對"以學習者為中心"和從"個性化學習"、"精準教學"視角出發的教育資源配置問題提供了理論"支持\\以及"方向指導...對於英文引號來說不區分前引號和後引號,怎麼能保證配置到的不會是 "和從"、"、" 以及 "以學習者為中心"和從"個性化學習"、"精準教學" 或者 不會忽略兩個引號出現在上下行的情況?
重溫正則表達式,終於得到如下表達式:
?::為了取消圓括號模式配置過程的緩存,即不需要遇到一個符合的就結束匹配[^"]:表示匹配的內容不能是 ",以避免貪婪匹配,即避免匹配成 從第一個 " 開始一直到最後一個 "結束整體的意思是 配置兩個 " 之間的內容,且內容中不包括 "後來整理過程中,還發現另一種寫法:
不過 . 不能匹配換行符\n,堅持要用,需要使用 可選修飾符 re.S:
import repattern = re.compile('".*?"', re.S)
re.findAll(pattern, text) # text 為待查找字符串re.S 為可選標識修飾符,使 . 匹配包括換行在內的所有字符關於 Python 正在表達式的更多用法參考文後參考連結
實現查找問題解決了,做替換就方便多了:
from docx import Documentimport re
doc = Document(r"D:\論文.docx")restr = '"(?:[^"])*"'
for p in doc.paragraphs: matchRet = re.findall(restr, p.text) for r in matchRet: p.text = p.text.replace(r, '「' + r[1:-1] + '」')doc.save(r'D:\論文_修正.docx')打開目標文檔,字符串前的 r 表示取消字符串轉義,即按原始字符產來解釋循環文檔的 段落(paragraph),對每個段落,用正則表達式進行匹配循環對於匹配到的結果,將前後引號,換成中文引號,並替換 段落(paragraph)的 text;其中 r[1:-1] 表示截取從第二個位置(第一個位置是 0)到倒數第二個位置截取字符串,剛好去掉前後引號注意:python-docx 保存文檔時不會給出任何提示,會瞬間完成,所以另存是個穩妥的做法
完工,趕緊將替換好的文檔發過去……
還沒來得回味,她說:「非常感謝!那個~ 能不能再幫我生成個圖表目錄,這個必須要……」
好吧,能者多勞(神器在手),幹就完了……
強大的 python-docx在上面小試牛刀中,介紹了插入段落(paragraph)的用法,下面在介紹一些 python-docx 的其他功能
為了簡潔,下面例子中省略了 Document 類的引入和實例化代碼,document 為 Document 的實例
添加標題默認情況下添加的標題是最高一級的,即一級標題,通過參數 level 設定,範圍是 1 ~ 9,也有 0 級別,表示的是段落標題:
# 添加一級標題document.add_heading('我是一級標題')
decument.add_heading('我是二級標題', level=2)
decument.add_heading('我是段落標題', level=0)添加換頁如果一個段落不滿一頁,需要分頁時,可以插入一個分頁符,直接調用會將分頁符插入到最後一個段落之後:
# 文檔最後插入分頁document.add_page_break()
# 特定段落分頁from docx.enum.text import WD_BREAKparagraph = document.add_paragraph("獨佔一頁") # 添加一個段落paragraph.runs[-1].add_break(WD_BREAK.PAGE) # 在段落的最後一個節段後添加分頁表格操作Word 文檔中經常會用到表格,python-docx 如何添加和操作表格呢?
# 添加一個 2×2 表格table = document.add_table(rows=2, cols=2)
# 獲取第一行第二列單元格cell = table.cell(0, 1)
# 設置單元格文本cell.text = '我是單元格文字'
# 表格的行row = table.rows[1]row.cells[0].text = 'Foo bar to you.'row.cells[1].text = 'And a hearty foo bar to you too sir!'
# 增加行row = table.add_row()更複雜點的例子:
# 表格數據items = ( (7, '1024', '手機'), (3, '2042', '筆記本'), (1, '1288', '臺式機'),)
# 添加一個表格table = document.add_table(1, 3)
# 設置表格標題heading_cells = table.rows[0].cellsheading_cells[0].text = '數量'heading_cells[1].text = '編碼'heading_cells[2].text = '描述'
# 將數據填入表格for item in items: cells = table.add_row().cells cells[0].text = str(item[0]) cells[1].text = item[1] cells[2].text = item[2]添加圖片添加圖片,即,為 Word 裡 菜單中 插入 > 圖片 插入的功能,插入圖片為原始大小:
document.add_picture('image-filename.png')插入時設置圖片大小:
from docx.shared import Cm# 設置圖片的跨度為 10 釐米document.add_picture('image-filename.png', width=Cm(10))除了釐米,python-docx 還提供了 英寸(Inches),如設置 1英寸: Inches(1.0)
樣式樣式可以針對整體文檔(document)、段落(paragraph)、節段(run),月具體,樣式優先級越高
python-docx 樣式功能配置多樣,功能豐富,這裡對段落樣式和文字樣式做簡單介紹
段落樣式段落樣式包括:對齊、列表樣式、行間距、縮進、背景色等,可以在添加段落時設定,也可以在添加之後設置:
# 添加一個段落,設置為無序列表樣式document.add_paragraph('我是個無序列表段落', style='List Bullet')
# 添加段落後,通過 style 屬性設置樣式paragraph = document.add_paragraph('我也是個無序列表段落')paragraph.style = 'List Bullet'文字樣式在前面 python-docx 文檔結構圖可以看到,段落中,不同樣式的內容,被劃分成多個 節段(Run),文字樣式是通過 節段(Run)來設置的
設置加粗/斜體paragraph = document.add_paragraph('添加一個段落')# 設置 節段文字為加粗run = paragraph.add_run('添加一個節段')run.bold = True
# 設置 節段文字為斜體run = paragraph.add_run('我是斜體的')run.italic = True設置字體設置字體稍微複雜些,例如設置一段文字為 宋體:
paragraph = document.add_paragraph('我的字體是 宋體')run = paragraph.runs[0]run.font.name = '宋體'run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋體')總結python-docx 是個功能強大的 Word 庫,能實現幾乎所有在 Word 中操作,今天通過一個實例,介紹了 python-docx 的一些基本用法,限於篇幅,沒法展開討論更多內容,如果有興趣可以深入研究,說不定可以讓 Word 像 Markdown 一樣簡單。
參考https://python-docx.readthedocs.io/en/latest/
https://www.runoob.com/python/python-reg-expressions.html
https://www.cnblogs.com/nixindecat/p/12157623.html