将 JavaScript 源码整理为可交付的 Word 文档,常见于代码审计报告、技术文档归档和教学材料准备。难点不在写入,而在保真:Word 不能直接理解 JS 语法,纯文本粘贴会丢失缩进、换行和着色。可行路径是把语法理解与文档承载拆开:先用 Pygments 将源码渲染为带内联样式的 HTML,再用 Spire.Doc for Python 构建 .docx 并导入 HTML。整个流程可在 Python 脚本内完成。
依赖安装:- pip install spire.doc
- pip install pygments
复制代码
单文件转换实现:- from spire.doc import *
- from pygments import highlight
- from pygments.lexers import JavascriptLexer
- from pygments.formatters import HtmlFormatter
- # 将 JavaScript 文件转换为带有语法高亮的 Word 文档
- def convert_js_to_word(input_file: str, output_file: str) -> None:
- with open(input_file, 'r', encoding='utf-8') as file:
- js_code = file.read()
- document = Document()
- section = document.AddSection()
- section.PageSetup.Margins.All = 50
- title_paragraph = section.AddParagraph()
- title_text = title_paragraph.AppendText(f'源代码:{input_file}')
- title_text.CharacterFormat.FontName = '微软雅黑'
- title_text.CharacterFormat.FontSize = 14
- title_text.CharacterFormat.Bold = True
- title_paragraph.Format.AfterSpacing = 10
- html_formatter = HtmlFormatter(
- nowrap=True,
- style='colorful',
- noclasses=True
- )
- highlighted_html = highlight(js_code, JavascriptLexer(), html_formatter)
- code_paragraph = section.AddParagraph()
- code_paragraph.AppendHTML(
- f'<pre style="font-family: Consolas; font-size: 10pt;">{highlighted_html}</pre>'
- )
- document.SaveToFile(output_file, FileFormat.Docx)
- document.Close()
- print(f'已将 {input_file} 转换为 {output_file}')
- convert_js_to_word('app.js', 'JavaScriptCode.docx')
复制代码
关键参数中,noclasses=True 决定着色能否保留。它把颜色样式以内联方式写入 HTML 标签,而不是输出 class 交给外部样式表。Word 导入 HTML 时通常不加载外部 CSS,省略该参数会导致代码只有文本没有颜色。外层 pre 标签不能省,否则连续空白与换行会被合并,缩进随之塌陷。nowrap=True 用于避免每行末尾额外换行,防止 Word 中出现多余空行。style 可换成 monokai、vim、vs 等内置配色,属于阅读偏好;Margins.All = 50 收窄页边距,为长代码行争取横向空间;Consolas 等宽字体用于保持对齐稳定。
如果源码是 React 的 JSX,JavascriptLexer 对组件标签与 {} 内表达式的切分不够准确,着色可能错位。此时换用 JsxLexer,其余流程不变:- from pygments.lexers import JsxLexer
- highlighted_html = highlight(jsx_code, JsxLexer(), html_formatter)
复制代码
这反映出一个更一般的约束:词法器选择直接决定输出质量。Pygments 覆盖范围虽广,但对 TypeScript 装饰器、较新的语法提案等方言仍可能存在识别滞后。转换前确认词法器与源码方言匹配,比事后修补格式更省力。
单文件跑通后,批量处理是自然下一步:遍历目录、按扩展名筛选、逐个调用转换函数。这里有两个容易忽略的工程约束。其一是资源释放,循环中每次都应调用 document.Close(),否则文档对象累积会推高内存占用。其二是编码,非 UTF-8 源文件需显式指定 encoding,带 BOM 的文件用 utf-8-sig 读取,否则中文注释可能乱码。超大文件如上万行会暴露另一层限制:一次性渲染 HTML 并导入,生成过程明显变慢。分块处理是一种折中,但分块会切断跨行的语法结构,多行字符串、块注释、模板字面量都可能在切分点被破坏,因此能否分块取决于这类结构的密度,而非单纯的行数。
除了 Spire.Doc + Pygments,还可以用 python-docx + Pygments 做免费开源方案。python-docx 本身不直接解析 HTML,需要手动把 Pygments token 写入段落:用 lex() 得到 (tokentype, value) 序列,按 token 类型映射字体颜色,再用 add_run() 写入。下面是简化示例,实际应用需更精细的 token 到颜色映射,并处理换行与背景色:- from docx import Document
- from docx.shared import Pt, RGBColor
- from pygments import lex
- from pygments.lexers import JavascriptLexer
- from pygments.styles import get_style_by_name
- def convert_js_to_word_manual(input_file, output_file):
- with open(input_file, 'r', encoding='utf-8') as f:
- code = f.read()
- doc = Document()
- paragraph = doc.add_paragraph()
- paragraph.style.font.name = 'Consolas'
- paragraph.style.font.size = Pt(10)
- style = get_style_by_name('colorful')
- token_color_map = {
- 'Token.Keyword': RGBColor(0x00, 0x00, 0xFF),
- 'Token.String': RGBColor(0x00, 0x80, 0x00),
- 'Token.Comment': RGBColor(0x80, 0x80, 0x80),
- }
- for token_type, value in lex(code, JavascriptLexer()):
- run = paragraph.add_run(value)
- for token_name, color in token_color_map.items():
- if str(token_type).startswith(token_name):
- run.font.color.rgb = color
- break
- run.font.name = 'Consolas'
- run.font.size = Pt(10)
- doc.save(output_file)
复制代码
若目标是批量处理整个项目的代码用于归档或软著申请,并且不需要语法高亮,可考虑 GitHub 上的 export_code_to_docx 工具。先安装 python-docx,再按示例命令运行:- pip install python-docx
- python export_code_to_docx.py --include ./src --ext js --output my_code.docx --no-comments
复制代码 该工具支持目录递归、扩展名过滤、排除路径、中文路径等,适合快速生成纯文本形式的代码文档;示例中的 --no-comments 可按实际需求调整。
这套代码到 HTML 再到 Word 的管道,价值在于可复现与可批量化:转换逻辑全部由脚本控制,能嵌入构建流程,源码更新后重跑即可得到同步文档。但能力上限由 Word 对 HTML/CSS 的支持范围决定,侧边标注、折叠区域、跨页断行控制等复杂代码布局无法通过这条路径还原,精细排版仍需在 Word 内二次加工,或改用 LaTeX、Pandoc 等以排版为核心的方案。它适合结构清晰、以内容归档为目的的场景,不适合以版式设计为核心的交付物。 |