iT邦幫忙

0

python for迴圈問題2

  • 分享至 

  • xImage

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)

看更多先前的討論...收起先前的討論...
tryit iT邦研究生 4 級 ‧ 2022-12-15 19:05:06 檢舉
你要附上你的error code
您好,沒有error,完成的word頁面,第一頁是最後一頁,然後中間234頁是空白,第5頁有前面4頁的內容。
小哈片刻 iT邦研究生 4 級 ‧ 2022-12-15 22:29:13 檢舉
你要貼一下 e 和 a 大概是怎麼來的
這樣看不懂
e和a 就是數字5 喔,謝謝。
re.Zero iT邦研究生 5 級 ‧ 2022-12-16 16:12:53 檢舉
「e和a 就是數字5 」!?你嚇到我了。我去測試一下,不管用 [ a=5; len(a) ] 還是 [ len(5) ] 去跑,Python 都回我「 TypeError: object of type 'int' has no len() 」…… (我還想說 Python 何時變得這麼神奇了~)
你想表達的是「 len(a) 和 len(e) 就是數字5 喔」這個吧?(雖說這不是對方想要的答案。)
???哦,對,我說的太簡短了,其實原意是,len(e)和len(a)產生的結果都是數字5,亦即range(5)的效果。
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

0
小哈片刻
iT邦研究生 4 級 ‧ 2022-12-15 22:36:23
最佳解答

應該是在後期的迴圈,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.add_paragraph(a[n])指給變數就成功了。

其實我覺得有點奇怪,
為什麼「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之類的。
可是結果就是如同小哈片刻所言,
實在很離奇。

小哈片刻 iT邦研究生 4 級 ‧ 2022-12-16 22:24:17 檢舉

因為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

以此類推

有的,我剛才想起來……二維陣列其實是一維的擴展,我把它立體化了,忘記它是平面的,謝謝您。

0
re.Zero
iT邦研究生 5 級 ‧ 2022-12-16 19:13:32

就我的感覺,你的問題不是在於 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 呢~
所以此時我會再檢查一次流程與邏輯,確認:

  • 當初規劃的 m 該用在哪?
  • 該用 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語法學自哪本書,不勝感激。

re.Zero iT邦研究生 5 級 ‧ 2022-12-16 23:22:37 檢舉

所以你是基礎沒學好就看應用方面的書?有好有壞~反正一路上有學友相伴應該是沒啥問題;頂多多點碰撞,多點經驗!加油!

至於我學 Python ,並沒看書耶,主要研習來源是網路的官方文件與案例吧。

我因為喜好而學過不少程式語言,最關鍵還是 C 吧;有看書學的就 C 與 Java,後來學其他程式語言都是邊寫邊研究(翻網上官方文件與 Google)。

至於我用的語法有點誇張,多因有過去的經驗(所以你會看到我常用 Python 不推薦的寫法),再加上我是因為興趣而多在閒暇時邊研究案例邊撰寫的關係吧。

(畢竟網路上很多有趣的案例與寫法,多看多寫就多經驗,遇錯也能從解析中改進自身邏輯;然後就被一堆語法糖慣壞了~哈~)

所以我沒能提出給你參考的 Python 相關書目,抱歉。

Update: P.S.
我上述所寫的「官方文件」,不限於程式語言官方,還有程式庫、API 的官方文件(尤其是開源的程式碼,很多經過多人的錘鍊;在剖析時也能學到很多)。

小哈片刻 iT邦研究生 4 級 ‧ 2022-12-16 23:39:14 檢舉

自薦一下 https://youtu.be/0B0h4HlG6tA python的學習材料

感謝兩位m(__)m

b.paragraphs[n].runs[0].add_break(docx.enum.text.WD_BREAK.PAGE)
怎會用上這麼細膩的語法而不用官方簡要語法,令我好奇是為了解決啥問題而這樣用。

to : re.Zero
書裡沒有「換頁語法」但要求寫出這種效果啊,於是網上找解答。

我要發表回答

立即登入回答