57 lines
1.9 KiB
Python
57 lines
1.9 KiB
Python
"""Excel (.xlsx) → Markdown。每個工作表一節,內容輸出為 Markdown 表格。
|
||
|
||
可獨立執行:python tools/convert/from_xlsx.py <file.xlsx> [-o out.md] [--dry-run]
|
||
"""
|
||
import argparse
|
||
import pathlib
|
||
|
||
import openpyxl
|
||
|
||
|
||
def _cell(v):
|
||
return "" if v is None else str(v).replace("|", "\\|").replace("\n", " ").strip()
|
||
|
||
|
||
def convert(src, assets_dir=None, md_dir=None):
|
||
"""回傳 (markdown, status)。status 恆為 'ok'。
|
||
|
||
ponytail: merged cell 只有左上角有值(openpyxl read_only 行為),不展開;
|
||
升級路徑:非 read_only 模式讀 merged_cells.ranges 補值。
|
||
"""
|
||
wb = openpyxl.load_workbook(str(src), data_only=True, read_only=True)
|
||
sections = []
|
||
for ws in wb.worksheets:
|
||
rows = [[_cell(v) for v in row] for row in ws.iter_rows(values_only=True)]
|
||
rows = [r for r in rows if any(r)] # 去除全空列
|
||
body = f"## 工作表:{ws.title}\n\n"
|
||
if not rows:
|
||
body += "(空白工作表)"
|
||
else:
|
||
width = max(len(r) for r in rows)
|
||
rows = [r + [""] * (width - len(r)) for r in rows]
|
||
lines = ["| " + " | ".join(rows[0]) + " |", "|" + " --- |" * width]
|
||
lines += ["| " + " | ".join(r) + " |" for r in rows[1:]]
|
||
body += "\n".join(lines)
|
||
sections.append(body)
|
||
wb.close()
|
||
return "\n\n".join(sections), "ok"
|
||
|
||
|
||
def main(argv=None):
|
||
ap = argparse.ArgumentParser(description=__doc__)
|
||
ap.add_argument("src")
|
||
ap.add_argument("-o", "--output")
|
||
ap.add_argument("--dry-run", action="store_true")
|
||
a = ap.parse_args(argv)
|
||
md, status = convert(a.src)
|
||
if a.dry_run:
|
||
print(f"[dry-run] {a.src}: status={status}, {len(md)} chars")
|
||
return
|
||
out = pathlib.Path(a.output) if a.output else pathlib.Path(a.src).with_suffix(".md")
|
||
out.write_text(md, encoding="utf-8")
|
||
print(out)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|