# -*- coding: utf-8 -*- """Convert 9.19 markdown manuals to Word.""" import os, re from docx import Document from docx.shared import Pt, Cm, RGBColor from docx.oxml.ns import qn from docx.enum.text import WD_ALIGN_PARAGRAPH from docx.enum.table import WD_TABLE_ALIGNMENT SRC = r"D:\产线\大洋\大洋操作手册汇总9.19" FONT = "微软雅黑" def set_run_font(run, size=11, bold=False, color=None): run.bold = bold run.font.size = Pt(size) run.font.name = FONT r = run._element rPr = r.get_or_add_rPr() rFonts = rPr.find(qn("w:rFonts")) if rFonts is None: from lxml import etree rFonts = rPr.makeelement(qn("w:rFonts"), {}) rPr.append(rFonts) rFonts.set(qn("w:eastAsia"), FONT) rFonts.set(qn("w:ascii"), FONT) rFonts.set(qn("w:hAnsi"), FONT) if color: run.font.color.rgb = RGBColor(*color) def add_runs(p, text, size=11, bold=False): # split **bold** parts = re.split(r"(\*\*[^*]+\*\*)", text) for part in parts: if part.startswith("**") and part.endswith("**"): run = p.add_run(part[2:-2]) set_run_font(run, size=size, bold=True) else: run = p.add_run(part) set_run_font(run, size=size, bold=bold) def parse_table(lines, i): rows = [] while i < len(lines) and lines[i].startswith("|"): raw = [c.strip() for c in lines[i].strip().strip("|").split("|")] if not re.match(r"^:?-+:?$", raw[0].replace(" ", "")): rows.append(raw) i += 1 return rows, i def convert(md_path, docx_path): text = open(md_path, encoding="utf-8").read() lines = text.splitlines() doc = Document() section = doc.sections[0] section.top_margin = Cm(2) section.bottom_margin = Cm(2) section.left_margin = Cm(2.2) section.right_margin = Cm(2.2) style = doc.styles["Normal"] style.font.name = FONT style.font.size = Pt(11) style.element.rPr.rFonts.set(qn("w:eastAsia"), FONT) i = 0 while i < len(lines): line = lines[i].rstrip() if not line: i += 1 continue if line.startswith("# "): p = doc.add_heading("", level=0) p.clear() run = p.add_run(line[2:].strip()) set_run_font(run, size=18, bold=True, color=(0x1F, 0x4E, 0x79)) i += 1 continue if line.startswith("## "): p = doc.add_heading("", level=1) p.clear() run = p.add_run(line[3:].strip()) set_run_font(run, size=16, bold=True, color=(0x2E, 0x75, 0xB6)) i += 1 continue if line.startswith("### "): p = doc.add_heading("", level=2) p.clear() run = p.add_run(line[4:].strip()) set_run_font(run, size=14, bold=True, color=(0x2E, 0x75, 0xB6)) i += 1 continue if line.startswith("#### "): p = doc.add_heading("", level=3) p.clear() run = p.add_run(line[5:].strip()) set_run_font(run, size=12, bold=True) i += 1 continue if line.startswith("---"): i += 1 continue if line.startswith("|"): rows, i = parse_table(lines, i) if rows: cols = max(len(r) for r in rows) table = doc.add_table(rows=len(rows), cols=cols) table.style = "Table Grid" table.alignment = WD_TABLE_ALIGNMENT.CENTER for r_idx, row in enumerate(rows): for c_idx in range(cols): cell = table.cell(r_idx, c_idx) cell.text = "" p = cell.paragraphs[0] val = row[c_idx] if c_idx < len(row) else "" add_runs(p, val, size=10, bold=(r_idx == 0)) continue if line.startswith("- "): p = doc.add_paragraph(style="List Bullet") p.clear() add_runs(p, line[2:].strip()) i += 1 continue if re.match(r"^\d+\.\s", line): p = doc.add_paragraph(style="List Number") p.clear() add_runs(p, re.sub(r"^\d+\.\s", "", line)) i += 1 continue p = doc.add_paragraph() add_runs(p, line) i += 1 doc.save(docx_path) print("saved", os.path.basename(docx_path)) def main(): files = [f for f in os.listdir(SRC) if f.endswith(".md")] files.sort() for f in files: md = os.path.join(SRC, f) docx = os.path.join(SRC, os.path.splitext(f)[0] + ".docx") convert(md, docx) if __name__ == "__main__": main()