用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文档,包含一个或多个sectionsconst 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、关键技术原理详解

  1. Word文档解析:

    • mammoth库解析.docx文件(实际是ZIP压缩包),提取其中的document.xml文件内容
    • 解析XML结构,提取所有文本节点,忽略格式、图片等非文本元素
  2. 差异比较算法:

    • diff库使用Myers差分算法找出两个文本序列的最长公共子序列(LCS)
    • diffWords方法进行单词级别的比较,比字符级比较更符合文档比较的需求
  3. Word文档生成:

    • docx库构建符合Office Open XML标准的Word文档结构
    • 文档结构包含段落(Paragraph)、文本块(TextRun)等元素
    • 颜色使用16进制RGB格式表示(如1800a1表示蓝色)
  4. 差异可视化:

    • 新增内容用蓝色加粗显示,便于识别添加的内容
    • 删除内容用红色删除线显示,表示已移除的内容
    • 保留原始文本的段落结构,确保可读性
  5. 文件处理:

    • 最终生成的.docx文件实际上是包含多个XML文件的ZIP压缩包
    • Packer.toBuffer方法将内存中的文档结构打包成符合标准的.docx文件

结语:让机器做枯燥的事,让人做有创意的事
通过这个项目,我们不仅实现了一个实用的文档比对工具,更演示了如何:
🔧 组合现有工具解决实际问题
🚀 用少量代码创造高价值产出
🌐 将复杂技术转化为简单接口

下次当同事还在用"Ctrl+F"艰难找不同时,你可以优雅地说:“试试我的智能比对工具?”

原创技术博客,转载请注明出处。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/77419.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端浏览器窗口交互完全指南:从基础操作到高级控制

浏览器窗口交互是前端开发中构建复杂Web应用的核心能力&#xff0c;本文深入探讨23种关键交互技术&#xff0c;涵盖从传统API到最新的W3C提案&#xff0c;助您掌握跨窗口、跨标签页的完整控制方案。 一、基础窗口操作体系 1.1 窗口创建与控制 // 新窗口创建&#xff08;现代浏…

Git和Gitlab的部署和操作

一。GIT的基本操作 1.GIT的操作和查看内容 [rootmaster ~]# yum install git -y [rootmaster ~]# git config --list&#xff1a;查看所有配置 2.GIT仓库初始化 [rootmaster ~]# mkdir /gittest&#xff1a;创建目录 [rootmaster ~]# cd /gittest/&#xff1a;进入目录 [rootm…

Linux中线程池的简单实现 -- 线程安全的日志模块,策略模式,线程池的封装设计,单例模式,饿汉式单例模式,懒汉式单例模式

目录 1. 对线程池的理解 1.1 基本概念 1.2 工作原理 1.3 线程池的优点 2. 日志与策略模式 2.1 日志认识 2.2 策略模式 2.2.1 策略模式的概念 2.2.2 工作原理 2.2 自定义日志系统的实现 3. 线程池设计 3.1 简单线程池的设计 3.2 线程安全的单例模式线程池的设计 3…

量子力学:量子通信

量子通信是利用量子力学原理对信息进行编码、传输和处理的新型通信方式&#xff0c;以下是其详细介绍及业界发展现状&#xff1a; 基本原理 量子叠加态 &#xff1a;量子系统可以处于多个状态的叠加&#xff0c;如光子的偏振方向可以同时处于水平和垂直方向的叠加态&#xff…

企业架构之旅(1):TOGAF 基础入门

大家好&#xff0c;我是沛哥儿。今天我们简单聊下TOGAF哈。 文章目录 一、TOGAF 是什么定义与核心定位发展历程与行业地位与其他架构框架的区别 二、TOGAF 核心价值企业数字化转型助力业务与 IT 的协同作用降本增效与风险管控 三、TOGAF 基础术语解析架构域&#xff08;业务、…

CSS 内容超出显示省略号

CSS 内容超出显示省略号 文章目录 CSS 内容超出显示省略号**1. 单行文本省略&#xff08;常用&#xff09;****2. 多行文本省略&#xff08;如 2 行&#xff09;****3. 对非块级元素生效****完整示例****注意事项** 在 CSS 中实现内容超出显示省略号&#xff0c;主要通过控制文…

路由器重分发(OSPF+RIP),RIP充当翻译官,OSPF充当翻译官

路由器重分发&#xff08;OSPFRIP&#xff09; 版本 1 RIP充当翻译官 OSPF路由器只会OSPF语言&#xff1b;RIP路由器充当翻译官就要会OSPF语言和RIP语言&#xff1b;则在RIP中还需要将OSPF翻译成RIPOSPF 把RIP路由器当成翻译官&#xff0c;OSPF路由器就只需要宣告自己的ip&am…

AlexNet网络搭建

AlexNet网络模型搭建 环境准备 首先在某个盘符下创建一个文件夹&#xff0c;就叫AlexNet吧&#xff0c;用来存放源代码。 然后新建一个python文件&#xff0c;就叫plot.py吧&#xff0c;往里面写入以下代码&#xff0c;用于下载数据集&#xff1a; # FashionMNIST里面包含了…

【计算机网络】网络基础概念

&#x1f4da; 博主的专栏 &#x1f427; Linux | &#x1f5a5;️ C | &#x1f4ca; 数据结构 | &#x1f4a1;C 算法 | &#x1f152; C 语言 | &#x1f310; 计算机网络 这是博主计算机网络的第一篇文章&#xff0c;本文由于是基础概念了解&#xff0c;引用了大…

在Spring Boot项目中实现Word转PDF并预览

在Spring Boot项目中实现Word转PDF并进行前端网页预览&#xff0c;你可以使用Apache POI来读取Word文件&#xff0c;iText或Apache PDFBox来生成PDF文件&#xff0c;然后通过Spring Boot控制器提供文件下载或预览链接。以下是一个示例实现步骤和代码&#xff1a; 1. 添加依赖 …

图解 Redis 事务 ACID特性 |源码解析|EXEC、WATCH、QUEUE

写在前面 Redis 通过 MULTI、EXEC、WATCH 等命令来实现事务功能。Redis的事务是将多个命令请求打包&#xff0c;然后一次性、按照顺序的执行多个命令的机制&#xff0c;并且在事务执行期间&#xff0c;服务器不会中断事务而该去执行其他客户端的命令请求。 就像下面这样&#…

LeetCode --- 446 周赛

题目列表 3522. 执行指令后的得分 3523. 非递减数组的最大长度 3524. 求出数组的 X 值 I 3525. 求出数组的 X 值 II 一、执行指令后的得分 照着题目要求进行模拟即可&#xff0c;代码如下 // C class Solution { public:long long calculateScore(vector<string>&…

山东大学软件学院项目实训-基于大模型的模拟面试系统-前端美化滚动条问题

模拟面试界面左侧底部 通过检查工具定位到其所在的位置&#xff1a; 直接对该组件进行美化&#xff1a; <!-- AI面试官列表 --><div class"ai-interviewer-section" v-show"activeTab interviewer"><el-scrollbar class"no-horizont…

git版本回退 | 远程仓库的回退 (附实战Demo)

目录 前言1. 基本知识2. Demo3. 彩蛋 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 爬虫神器&#xff0c;无代码爬取&#xff0c;就来&#xff1a;bright.cn 本身暂存区有多个文件&#xff0c;但手快了&…

什么事Nginx,及使用Nginx部署vue项目(非服务器Nginx压缩包版)

什么是 Nginx? Nginx(发音为 “engine-x”)是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。它以其高性能、高并发处理能力和低资源消耗而闻名。以下是 Nginx 的主要特性和用途: 主要特性 高性能和高并发 Nginx 能够处理大量并发连接,适合高…

第十六周蓝桥杯2025网络安全赛道

因为只会web&#xff0c;其他方向都没碰过&#xff0c;所以只出了4道 做出来的&#xff1a; ezEvtx 找到一个被移动的文件&#xff0c;疑似被入侵 提交flag{confidential.docx}成功解出 flag{confidential.docx} Flowzip 过滤器搜索flag找到flag flag{c6db63e6-6459-4e75-…

高性能的开源网络入侵检测和防御引擎:Suricata介绍

一、Debian下使用Suricata 相较于Windows&#xff0c;Linux环境对Suricata的支持更加完善&#xff0c;操作也更为便捷。 1. 安装 Suricata 在Debian系统上&#xff0c;你可以通过包管理器 apt 轻松安装 Suricata。 更新软件包列表: sudo apt update安装 Suricata: sudo apt …

IP-address-space

导航 (返回顶部) 1. IPv4地址分配表 1.2 IPv4 专用地址注册表1.3 各国IPv4地址分配列表 2. IPv6地址分配表 2.1 IANA IPv6 专用地址注册表2.2 IPv6 多播地址分配 1. IPv4地址分配表1.2 IPv4 专用地址注册表1.3 各国IPv4地址分配列表 2. IPv6地址分配表2.1 IANA IPv6 专用地址…

Ubuntu使用war包部署Jenkins并通过systemcl管理

目录 一、当前系统环境 二、安装Java 二、安装Jenkins 三、使用systemctl管理 一、当前系统环境 操作系统&#xff1a;ubuntu 24.04 Jenkins版本&#xff1a;2.506 格式&#xff1a;war JDK版本&#xff1a;OpenJDK_17 二、安装Java 1.下载jdk安装包 # wget下载 wget …

牛客 verilog入门 VIP

1、输出1 答案&#xff1a; timescale 1ns/1nsmodule top_module(output wire one );assign one 1b1; endmodule 2、wire连线 答案&#xff1a; timescale 1ns/1nsmodule wire0(input wire in0,output wire out1 );assign out1 in0; endmodule 3、多wire连线 timescale 1…