Phase 2: 轉換管線 — 五個本地轉換器 + convert.py 統一入口 + selfcheck
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
56
tools/convert/from_xlsx.py
Normal file
56
tools/convert/from_xlsx.py
Normal file
@@ -0,0 +1,56 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user