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 計算出的總和。試算表必須能在輸入值變動時重新計算。 - 嚴格遵循使用者的規格。 確切的分頁名稱、確切的欄標題,以及使用者明確說明的公式。任何重新設計但計算出不同結果的方案,無論多優雅都視為失敗。
- 記錄每個假設與硬編碼的數字,放在讀者會看到的地方——儲存格註解,或表格結尾的相鄰儲存格。如果有真實來源,請引用(
來源:公司 10-K,FY2024,第 45 頁,收入附註,[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是唯讀的。 .xlsm檔案會失去其巨集,除非您在load_workbook中傳入keep_vba=True。- 包含空白的工作表名稱必須在跨工作表參照中加上引號:
='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 為沙箱環境自動配置)