"""Excel (.xlsx) → Markdown。每個工作表一節,內容輸出為 Markdown 表格。 可獨立執行:python tools/convert/from_xlsx.py [-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()