使用Node.js实现Word文档差异比较并高亮标注工具
作者:青霄客
这篇文章主要介绍了一个使用Node.js编写的智能Word文档差异比对工具,通过解析、比较和生成Word文档,实现自动识别文本差异、智能标注修改痕迹并生成专业比对报告,感兴趣的小伙伴跟着小编一起来看看吧
引言
当「找不同」遇上程序员的智慧
你是否经历过这样的场景?
法务同事发来合同第8版修改版,却说不清改了哪里
导师在论文修改稿里标注了十几处调整,需要逐一核对
团队协作文档频繁更新,版本差异让人眼花缭乱
传统的手动比对不仅效率低下,还容易遗漏关键修改。今天,我将揭秘如何用30行Node.js代码,打造一个智能Word文档差异比对工具,实现:
- 自动识别文本差异
- 智能标注修改痕迹
- 生成专业比对报告
一、安装所需依赖
npm install docx mammoth diff fs-extra
二、代码注释与技术原理详解
1、完整代码以及注释
/** * Word文档差异比较工具 * 本脚本使用Node.js比较两个Word(.docx)文件的内容差异,并生成带有颜色标注的比较结果文档 */ const fs = require('fs'); const path = require('path'); const { Document, Paragraph, TextRun, HeadingLevel, Packer } = require('docx'); const mammoth = require('mammoth'); const diff = require('diff'); /** * 比较两个Word文件并生成差异报告 * @param {string} file1Path - 第一个Word文件路径(原始文件) * @param {string} file2Path - 第二个Word文件路径(修改后的文件) * @param {string} outputPath - 差异报告输出路径 * * 技术原理: * 1. 使用mammoth库提取两个Word文档的纯文本内容 * 2. 使用diff库进行文本差异比较,识别添加、删除和未更改的部分 * 3. 使用docx库构建新的Word文档,用不同颜色和样式标注差异部分 */ async function compareWordFiles(file1Path, file2Path, outputPath) { try { // 提取两个Word文件的文本内容 // mammoth.extractRawText会解析docx文件的XML结构,提取所有文本内容 const file1Content = await extractTextFromDocx(file1Path); const file2Content = await extractTextFromDocx(file2Path); // 使用diff库比较文本差异 // diffWords函数会将文本分解为单词级别的差异,返回一个差异对象数组 // 每个差异对象包含value(文本内容)和added/removed标志 const differences = diff.diffWords(file1Content, file2Content); // 使用docx库创建新的Word文档 // Document对象表示整个Word文档,包含一个或多个sections const doc = new Document({ sections: [{ properties: {}, children: [ // 文档标题 new Paragraph({ text: "Word文档差异比较结果", heading: HeadingLevel.HEADING_1, spacing: { after: 200 } // 设置段后间距(单位:twip,1/20磅) }), // 原始文件信息 new Paragraph({ text: `原文件: ${path.basename(file1Path)}`, spacing: { after: 100 } }), // 修改后文件信息 new Paragraph({ text: `新文件: ${path.basename(file2Path)}`, spacing: { after: 200 } }), // 插入差异内容段落 ...generateDiffParagraphs(differences) ] }] }); // 将Document对象转换为Buffer并写入文件 // Packer.toBuffer内部使用JSZip库打包docx文件(本质上是ZIP格式的XML文件集合) const buffer = await Packer.toBuffer(doc); fs.writeFileSync(outputPath, buffer); console.log(`差异比较结果已保存到: ${outputPath}`); } catch (error) { console.error('比较过程中出错:', error); } } /** * 从Word文档中提取纯文本内容 * @param {string} filePath - Word文件路径 * @returns {Promise<string>} 提取的纯文本内容 * * 技术原理: * mammoth库解析docx文件(实际是ZIP压缩的XML文件), * 遍历document.xml中的段落和文本节点,拼接成纯文本字符串 */ async function extractTextFromDocx(filePath) { const result = await mammoth.extractRawText({ path: filePath }); return result.value; } /** * 根据差异结果生成带有样式标注的段落数组 * @param {Array} differences - diff库生成的差异数组 * @returns {Array} 包含Paragraph对象的数组 * * 技术原理: * 1. 处理diff库输出的差异数组,每个部分可能是added/removed/unchanged * 2. 按换行符分割文本,确保每个段落独立 * 3. 为不同差异类型创建不同样式的TextRun: * - 新增内容: 蓝色(#1800a1)、加粗 * - 删除内容: 红色(#FF0000)、删除线 * - 未更改内容: 黑色(#000000) */ function generateDiffParagraphs(differences) { const paragraphs = []; let currentParagraph = []; // 遍历每个差异部分 differences.forEach(part => { // 按换行符分割文本,处理多行内容 const lines = part.value.split('\n'); lines.forEach((line, lineIndex) => { // 跳过空行 if (line.trim() === '') return; let textRun; if (part.added) { // 新增内容样式 textRun = new TextRun({ text: line, color: '1800a1', // 蓝色表示新增 bold: true // 加粗突出显示 }); } else if (part.removed) { // 删除内容样式 textRun = new TextRun({ text: line, color: 'FF0000', // 红色表示删除 strike: true // 删除线表示已移除 }); } else { // 未更改内容样式 textRun = new TextRun({ text: line, color: '000000' // 黑色表示未更改 }); } // 将文本段添加到当前段落 currentParagraph.push(textRun); // 如果不是最后一行,创建新段落 if (lineIndex < lines.length - 1) { paragraphs.push(new Paragraph({ children: currentParagraph })); currentParagraph = []; // 重置当前段落 } }); }); // 添加最后一个未完成的段落 if (currentParagraph.length > 0) { paragraphs.push(new Paragraph({ children: currentParagraph })); } return paragraphs; } // 使用示例 const file1 = path.join(__dirname, './word/dl_v1.docx'); const file2 = path.join(__dirname, './word/js_xg_v1.docx'); const output = path.join(__dirname, './word/comparison_result.docx'); // 执行比较 compareWordFiles(file1, file2, output);
2、关键技术原理详解
Word文档解析:
mammoth
库解析.docx文件(实际是ZIP压缩包),提取其中的document.xml
文件内容- 解析XML结构,提取所有文本节点,忽略格式、图片等非文本元素
差异比较算法:
diff
库使用Myers差分算法找出两个文本序列的最长公共子序列(LCS)diffWords
方法进行单词级别的比较,比字符级比较更符合文档比较的需求
Word文档生成:
docx
库构建符合Office Open XML标准的Word文档结构- 文档结构包含段落(Paragraph)、文本块(TextRun)等元素
- 颜色使用16进制RGB格式表示(如
1800a1
表示蓝色)
差异可视化:
- 新增内容用蓝色加粗显示,便于识别添加的内容
- 删除内容用红色删除线显示,表示已移除的内容
- 保留原始文本的段落结构,确保可读性
文件处理:
- 最终生成的.docx文件实际上是包含多个XML文件的ZIP压缩包
Packer.toBuffer
方法将内存中的文档结构打包成符合标准的.docx文件
结语:让机器做枯燥的事,让人做有创意的事
通过这个项目,我们不仅实现了一个实用的文档比对工具,更演示了如何:
- 组合现有工具解决实际问题
- 用少量代码创造高价值产出
- 将复杂技术转化为简单接口
下次当同事还在用"Ctrl+F"艰难找不同时,你可以优雅地说:“试试我的智能比对工具?”
到此这篇关于使用Node.js实现Word文档差异比较并高亮标注工具的文章就介绍到这了,更多相关Node.js Word差异比较并标注内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!