Word 神器 python-docx

前兩天有個朋友向我求助,她在寫畢業論文時,不小心將論文裏的中文雙引號替換爲英文的了,各種原因導致無法回退,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 來安裝:

pip install python-docx

命令行中運行下面語句,如果沒有報錯,則說明安裝成功

$ 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")
  • 引入 Document 類

  • 定義一個新文檔對象 document

  • 想文檔中插入一個段落(paragraph)

  • 再在這個段落(paragraph)前插入另一個段落

  • 最後調用文檔對象 document 的 save 保存文檔

用 Word 打開保存的 test.docx 就可以看到:

問題分析與解決

瞭解了 python-docx 的基本概念,開始着手解決問題,大體思路是:

  1. 讀取文檔內容

  2. 查找 英文引號 之間的內容

  3. 將找到的內容的 英文引號 換成 中文引號,並將內容替換回去

  4. 完成處理後將文檔另存

查找目標

首先要解決的是如何找到 英文引號之間的內容?

例如文檔內容有這麼一段:

...
對"基於需求的教育資源配
置系統觀"的研究,尤其是對"以學習者爲中心"和從"個性化學習"、"精準教學"視角出發的
教育資源配置問題提供了理論"支持\\以及"方向指導
...

對於英文引號來說不區分前引號和後引號,怎麼能保證配置到的不會是 "和從""、" 以及 "以學習者爲中心"和從"個性化學習"、"精準教學" 或者 不會忽略兩個引號出現在上下行的情況?

重溫正則表達式,終於得到如下表達式:

'"(?:[^"])*"'
  • ?::爲了取消圓括號模式配置過程的緩存,即不需要遇到一個符合的就結束匹配

  • [^"]:表示匹配的內容不能是 ",以避免貪婪匹配,即避免匹配成 從第一個 " 開始一直到最後一個 "結束

  • 整體的意思是 配置兩個 " 之間的內容,且內容中不包括 "

後來整理過程中,還發現另一種寫法:

'".*?"'

不過 . 不能匹配換行符\n,堅持要用,需要使用 可選修飾符 re.S:

import re
pattern = re.compile('".*?"', re.S)


re.findAll(pattern, text)  # text 爲待查找字符串
  • 引入 正則表達式模塊 re

  • re.S 爲可選標識修飾符,使 . 匹配包括換行在內的所有字符

  • 利用 findAll 查找所有匹配內容

關於 Python 正在表達式的更多用法參考文後參考鏈接

實現

查找問題解決了,做替換就方便多了:

from docx import Document
import 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')
  • 引入 Document 類,和正則表達式模塊

  • 打開目標文檔,字符串前的 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_BREAK
paragraph = 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].cells
heading_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

代碼獲取方式

識別文末二維碼,回覆:666

PS:公號內回覆「Python即可進入 Python 新手學習交流羣,一起 100天計劃!

-END-

Python 技術

關於 Python 都在這裏

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章