python docx
總共5頁,每頁5句,每印完5句換頁
↓ 一直印錯。我的for思路好像有問題,請幫忙檢查一下。
(其實上一篇的問題也是for迴圈,但是從解答者的回答裡,我也看不出問題在哪?)
for m in range(len(e)): # 5 pages
for n in range(len(a)): # 5 paragraphs / per page
b.add_paragraph(a[n]) # a is a list , include 5 sentence
b.paragraphs[n].alignment = WD_ALIGN_PARAGRAPH.CENTER
if n==len(a)-1: # last sentence
b.paragraphs[n].add_run("kokoko") # add words and change page
b.paragraphs[n].runs[0].add_break(docx.enum.text.WD_BREAK.PAGE)
應該是在後期的迴圈,b.paragraphs一直取到舊的index
因為n只會在0-4之間跑
而b.paragraphs的index會從0到24
但你一直在拿0-4來操作b.paragraphs
for m in range(len(e)): # 5 pages
for n in range(len(a)): # 5 paragraphs / per page
b.add_paragraph(a[n]) # a is a list , include 5 sentence
pIndex = len(b.paragraphs) - 1
b.paragraphs[pIndex].alignment = WD_ALIGN_PARAGRAPH.CENTER
if n==len(a)-1: # last sentence
b.paragraphs[pIndex].add_run("kokoko") # add words and change page
b.paragraphs[pIndex].runs[0].add_break(docx.enum.text.WD_BREAK.PAGE)
其實我覺得有點奇怪,
為什麼「b.paragraphs的index會從0到24」會這樣???
我對兩層迴圈的理解如下↓
[m][n]=
[0][0]、[0][1]、[0][2]、[0][3]、[0][4]
[1][0]、[1][1]、[1][2]、[1][3]、[1][4]
以此類推直至[4][4]。
如果在頁[0]段落[4]加了換頁符號,
下一迴圈變成[1][0]時,就是進入word第2頁才對,
怎麼會整個走鐘???
n的範圍明明也是0~4,怎麼會跑成0~24或0~16之類的。
可是結果就是如同小哈片刻所言,
實在很離奇。
因為paragraphs本身是一個一維陣列
迴圈大概的走向是這樣
m = 0
n = 0
paragraphs加了新東西,這東西的index = 0
n = 1
paragraphs加了新東西,這東西的index = 1
n = 2
paragraphs加了新東西,這東西的index = 2
n = 3
paragraphs加了新東西,這東西的index = 3
n = 4
paragraphs加了新東西,這東西的index = 4
m = 1
n = 0
paragraphs加了新東西,這東西的index = 5
n = 1
paragraphs加了新東西,這東西的index = 6
n = 2
paragraphs加了新東西,這東西的index = 7
n = 3
paragraphs加了新東西,這東西的index = 8
n = 4
paragraphs加了新東西,這東西的index = 9
以此類推
有的,我剛才想起來……二維陣列其實是一維的擴展,我把它立體化了,忘記它是平面的,謝謝您。
就我的感覺,你的問題不是在於 for
loop 思路,而是在於「沒熟悉使用的工具就想順直覺用下去」。
(外加,對 Python 不熟?對寫上去卻沒用到的內容無感?這都經驗多了就 OK 了~(吧?))
因為你前三行看來邏輯正常:
for m in range(len(e)): # 5 pages
for n in range(len(a)): # 5 paragraphs / per page
b.add_paragraph(a[n]) # a is a list , include 5 sentence
但從 b.paragraphs[n].alignment = WD_ALIGN_PARAGRAPH.CENTER
開始我就覺得神奇了。
由 python-docx 生成的 docx 檔案簡略結構是:
<!--- 這是簡略示意用,缺省了很多東西! (made with "mySwitch=2";) -->
<w:document><w:body>
<!--- "<w:p>" 為 paragraph 元素, "<w:r>" 為 run 元素, "<w:t>" 為 text 元素 -->
<w:p><w:r><w:t>Sentence0001</w:t></w:r></w:p>
<w:p><w:r><w:t>Sentence0002</w:t></w:r></w:p>
<w:p><w:r><w:t>Sentence0003</w:t></w:r></w:p>
<w:p><w:r><w:t>Sentence0004</w:t></w:r></w:p>
<w:p>
<w:r><w:t>Sentence0005</w:t></w:r>
<w:r>
<w:t>kokoko</w:t>
<!--- "<w:br w:type="page"/>" 為 頁面類型的中斷(斷頁) 元素;可意表往後內容為下頁的內容 -->
<w:br w:type="page"/>
</w:r>
</w:p>
<!--- ... (後略:以頁為單位的重複內容) -->
</w:body></w:document>
而在你的程式內,至少會生成 5*5=25 個 <w:p>
,但你的程式一直在前五個作文字置中的操作;感覺你沒意識到文件結構(或誤會 python-docx 會自動換頁?),也沒意識到 m 怎沒在迴圈內被用到。
(話說,多數沒研究過的人應都認為文件就該以頁為單位,而很少意識到在 docx 是用中斷元素來分頁吧……)
其他讓我感到小奇怪的就是 runs
:
b.paragraphs[n].runs[0].add_break(docx.enum.text.WD_BREAK.PAGE)
怎會用上這麼細膩的語法而不用官方簡要語法,令我好奇是為了解決啥問題而這樣用。
且輸出感覺也看來怪怪的;這個部份我就懶得說了。
(因為不好解釋……我翻一些文件後覺得,驗證麻煩 + 太花時間……)
你可以在後續附上的我的版本中,修改 mySwitch ( 0 ~ 2 )看差異。
## 開頭不用管,建立測試環境;
## Python==3.8.16; python-docx==0.8.11;
import docx
from docx import Document
from docx.enum.text import WD_ALIGN_PARAGRAPH
##
myShowDebug = 1
##
b = Document()
e = [('Page'+'{:04d}'.format(i+1)) for i in range(5)]
a = [('Sentence'+'{:04d}'.format(i+1)) for i in range(5)]
if(myShowDebug):
for i in e: print(i,end=',')
print(';')
for i in a: print(i,end=',')
## 以下才是重要的;
for m in range(len(e)): # 5 pages
for n in range(len(a)): # 5 paragraphs / per page
b.add_paragraph(a[n]) # a is a list , include 5 sentence
## Hint: myList[-1] 指向 myList 物件的逆向第一個元素。(Python 內 Sequence Types 的能力)
b.paragraphs[-1].alignment = WD_ALIGN_PARAGRAPH.CENTER
if n==len(a)-1: # last sentence
b.paragraphs[-1].add_run("kokoko") # add words and change page
## @Next: 可修改 mySwitch (0~2) 觀察斷頁結果差異。
mySwitch = 0
if(mySwitch==1):
b.paragraphs[-1].runs[0].add_break(docx.enum.text.WD_BREAK.PAGE)
elif(mySwitch==2):
b.paragraphs[-1].runs[-1].add_break(docx.enum.text.WD_BREAK.PAGE)
else: ## @Next: 為官方簡要語法的增加斷頁元素,跟 mySwitch=2 的差異只能從 docx 檔案原始碼看出。
b.add_page_break()
## 以上才是重要的;
b.save('myTest01.docx')
恩,我的程式也沒用到 for
loop 的 m 呢~
所以此時我會再檢查一次流程與邏輯,確認:
b.paragraphs[-1]
)沒問題?判斷程式能正常運行再繼續。
(不過我平常就會先加一些 debug 用的程式碼(輸出關鍵變數、中斷執行等操作)以確認運行狀況。)
P.s. 有興趣的話,可用 7-Zip 等支援 zip 格式的軟體開啟 docx 檔案。(或追加.zip
為副檔名,用 Win 檔案總管開啟。)
由 "python-docx" 生成的 docx,可把裡面的 .\word\document.xml
解出丟給 Google Chrome 處理;能觀察上述三種 page break 加入方式在 python-docx 實作結果上的差異。
您的語法比較深,我還沒學到那麼多。
我的想法比較單純,就是兩層迴圈,
第一圈5頁,
第二圈是每頁5行。
我覺得奇怪的是,明明在當頁末加上換頁符號
為什麼跑起來不對?
後來是上面的朋友告知在取段落時,
一直停在最初的階段。
最後的程式長這樣↓
b = docx.Document()
c = open('p353c.txt')
d = c.read()
e = d.split("\n") # 5人人名
for m in range(len(e)): # 5 pages
for n in range(len(a)): # 5 paragraphs / per page
f = b.add_paragraph(a[n]) # ←改成這樣就解決了。
f.alignment = WD_ALIGN_PARAGRAPH.CENTER
if n%2==0: # 024三行
f.runs[0].italic = True # 斜體
if n==1: # 人名
f.text = e[m]
f.runs[0].bold = True # 粗體
f.runs[0].font.size = Pt(15) # 15號字
if n==len(a)-1: # 最後一行之後換頁
f.runs[0].add_break(docx.enum.text.WD_BREAK.PAGE)
順便提一下,我在學的這本python,盡可能的把python在很多方面的應用都擷取一小部份放進書裡做展示(例excel、pdf、word、regex、html...),極少提及python程式語法的觀念。而我僅知的兩層迴圈還是從c學來的,所以每次看到您的語法都有種大開眼界的感覺(很新鮮,看不懂),若能蒙您告知您的python語法學自哪本書,不勝感激。
所以你是基礎沒學好就看應用方面的書?有好有壞~反正一路上有學友相伴應該是沒啥問題;頂多多點碰撞,多點經驗!加油!
至於我學 Python ,並沒看書耶,主要研習來源是網路的官方文件與案例吧。
我因為喜好而學過不少程式語言,最關鍵還是 C 吧;有看書學的就 C 與 Java,後來學其他程式語言都是邊寫邊研究(翻網上官方文件與 Google)。
至於我用的語法有點誇張,多因有過去的經驗(所以你會看到我常用 Python 不推薦的寫法),再加上我是因為興趣而多在閒暇時邊研究案例邊撰寫的關係吧。
(畢竟網路上很多有趣的案例與寫法,多看多寫就多經驗,遇錯也能從解析中改進自身邏輯;然後就被一堆語法糖慣壞了~哈~)
所以我沒能提出給你參考的 Python 相關書目,抱歉。
Update: P.S.
我上述所寫的「官方文件」,不限於程式語言官方,還有程式庫、API 的官方文件(尤其是開源的程式碼,很多經過多人的錘鍊;在剖析時也能學到很多)。
自薦一下 https://youtu.be/0B0h4HlG6tA python的學習材料
感謝兩位m(__)m
to : re.Zero
書裡沒有「換頁語法」但要求寫出這種效果啊,於是網上找解答。