XLSX 建立、編輯與分析
| 任務 | 方法 |
|---|---|
| 建立或編輯含公式/格式 | openpyxl — 見下方注意事項 |
| 大量資料匯入/匯出 | pandas (read_excel, to_excel) |
| 快速查看工作表 | markitdown file.xlsx — 每個工作表顯示 ## SheetName;也能讀 .xlsm。不包含儲存格座標,因此不應用於規劃編輯 |
| 讀取模型(公式與值) | 兩次 load_workbook 呼叫 — 見注意事項 |
openpyxl、pandas與markitdown已預先安裝 — 請勿先執行pip install;直接編寫腳本並匯入即可。僅在匯入失敗(或缺少markitdown指令)時才使用pip install安裝遺失的套件。
以下腳本路徑均相對於此技能目錄。
每個輸出的要求
- 專業字型(Arial、Times New Roman)貫穿全文,除非使用者另有指定。
- 零公式錯誤。 絕不可在
recalc.py回報errors_found的情況下交付。若你認為錯誤在你之前就已存在,請證明:以data_only=True載入原始檔案並檢查該儲存格。你引入的錯誤與你繼承的錯誤看起來完全相同。 - 使用公式,絕不寫死結果。 寫
sheet['B10'] = '=SUM(B2:B9)',而非 Python 計算的總和。工作表必須能在輸入變更時重新計算。 - 嚴格遵循使用者的規格。 精確的分頁名稱、精確的欄位標題,以及他們指定的公式。一個計算其他內容的重新設計,無論多優雅,都是失敗。
- 在讀者能看到的地方記錄每個假設與寫死的數字 — 儲存格註解,或表格末端的相鄰儲存格。若有真實來源請引用(
Source: Company 10-K, FY2024, Page 45, Revenue Note, [SEC EDGAR URL]);若數字來自使用者,請清楚說明。 - 你建立來讓他人填寫的工作簿需要一個簡短的圖例說明哪些儲存格可以編輯,以及一個範例資料列顯示預期格式。切勿在要求你編輯的檔案中加入此類範例列。
- 編輯現有檔案:完全比照其慣例。 這些慣例優先於此處所有指南。先找出其指定的輸入儲存格 — 不同的字型顏色、填色或陰影會標示它們 — 僅在那裡寫入,並保持所有現有公式不變。
重新計算(只要檔案包含公式就必須執行)
openpyxl 將公式以無快取值的字串寫入。在你重新計算之前,任何讀取快取值的工具 — pandas、load_workbook(data_only=True) 以及大多數預覽器 — 都會將每個公式儲存格視為 None。
python scripts/recalc.py output.xlsx [timeout_seconds] # 預設 30
LibreOffice 會計算每個公式,檔案會原地重寫,並輸出 JSON:status(success | errors_found)、total_formulas、total_errors,以及一個 error_summary,其中每個錯誤類型會列出最多 100 個儲存格(locations_truncated 表示它隱藏了多少個 — 請相信 total_errors,而非列表長度)。修正它指出的錯誤後再次執行。JSON 中出現 error 鍵而非 status 表示未執行計算,僅此情況會以非零狀態碼退出 — errors_found 會以 0 退出,因此切勿將乾淨的退出視為乾淨的工作簿。
綠色的重新計算證明你的公式可以計算,但不代表它們正確。 一個差一格的範圍或對錯誤列的引用會產生一個乾淨、無錯誤但數字錯誤的檔案。在建立整個表格前,先寫 2–3 個公式並檢查它們是否拉取到預期的值。
連結到其他檔案的工作簿,如果你用 openpyxl 重新儲存然後重新計算,這些連結會遺失。這樣的公式會顯示 ='[1]Returns Analysis'!$B$2 — 其中的 [1] 是工作簿外部參考清單的索引,指向磁碟上另一個檔案,而非工作表。該檔案在此環境中很少存在,因此儲存格的快取值是唯一持有其資料的地方。openpyxl 在儲存時會清除該值;LibreOffice 接著必須真正解析該參考,但失敗了,寫入 #NAME?,並刪除所有連結。recalc.py 會拒絕在此狀態下執行 — 請在儲存前複製原始檔案中這些儲存格的值(使用 --force 會覆寫並接受資料遺失)。
選擇能通過驗證的公式
LibreOffice 實現的函數比 Excel 少,一個它無法計算的函數會變成字面上的 #NAME? 並嵌入你交付的檔案中。
- 優先使用 Excel 2007 時代的函數 —
SUMIFS、INDEX、MATCH、IFERROR、SUMPRODUCT— 這些不需要前綴。 - 六個 2007 之後的函數可以運作,但必須加上
_xlfn.前綴,因為 openpyxl 會將你的公式逐字寫入 XML,而 Excel 會為 2007 年之後的函數名稱加上前綴(其 UI 會隱藏該前綴):_xlfn.TEXTJOIN、_xlfn.CONCAT、_xlfn.IFS、_xlfn.SWITCH、_xlfn.MAXIFS、_xlfn.MINIFS。不帶前綴寫入時,每個都會產生#NAME?。 - 絕不使用
XLOOKUP、XMATCH、SORT、FILTER、UNIQUE或SEQUENCE。 運行時的 LibreOffice 在任何前綴下都無法計算它們。較新的版本可以計算,但它們是溢出陣列函數,而 openpyxl 寫入的檔案沒有溢出元數據,因此只有範圍的左上角儲存格會得到值 — 而recalc.py對這個截斷的結果會回報total_errors: 0。使用INDEX/MATCH進行查詢,並在寫入儲存格之前用 Python 進行排序、篩選和去重。 - 一個 LibreOffice 無法解析的公式會以小寫寫回 — 在
#NAME?旁邊是一個快速判斷點。
openpyxl 注意事項
- 讀取模型需要載入兩次。
data_only=True會產生快取值,但公式會消失;預設載入會得到公式字串但沒有值。一次載入無法同時取得兩者。 - 如果你儲存,
data_only=True具有破壞性。 該工作簿中已無公式,因此儲存會永久將每個公式替換為字面值。 - 對剛由 openpyxl 寫入的檔案使用
data_only=True會在所有地方回傳None— 請先執行recalc.py。(結果為""的公式也會回傳None。) - 合併儲存格:只寫入左上角的錨點。 範圍內的其他每個儲存格都是
MergedCell,其.value是唯讀的。 - 除非你傳入
keep_vba=True給load_workbook,否則.xlsm會遺失巨集。 - 包含空格的工作表名稱在跨工作表的參考中必須用引號括起來:
='Assumptions Inputs'!$B$5。未加引號時,會計算為#VALUE!。
財務模型
除非使用者另有說明,或現有檔案已採用其他做法。
顏色: 藍色文字 (0,0,255) 用於寫死的輸入和情境變數 · 黑色用於公式 · 綠色 (0,128,0) 用於連結到其他工作表 · 紅色 (255,0,0) 用於連結到其他檔案 · 黃色填色 (255,255,0) 用於關鍵假設和使用者應填寫的儲存格。
數字: 貨幣格式 $#,##0,並在標題中標示單位 (Revenue ($mm)) · 零顯示為 -,包含百分比 ($#,##0;($#,##0);-) · 負數用括號 · 百分比 0.0%,儲存為小數 (0.15 顯示為 15.0%;儲存 15 會顯示為 1500.0%) · 估值倍數 0.0x · 年份用文字 ("2024",絕不使用 2,024)。
結構: 每個假設放在其自己的標籤儲存格中,由使用它的公式參考 (=B5*(1+$B$6),絕不使用 =B5*1.05) · 公式在每個預測期間保持一致,因為中間某個被單獨編輯的儲存格是最常見的隱性錯誤 · 對可能為零的分母設置保護。
相依套件
openpyxl、pandas、markitdown(pip,已預先安裝 — 僅在匯入失敗或缺少指令時才安裝) · LibreOffice (soffice,已為沙盒環境自動配置,透過 scripts/office/soffice.py)