使用Node.js實現Word文檔差異比較并高亮標注工具
引言
當「找不同」遇上程序員的智慧
你是否經歷過這樣的場景?
法務同事發(fā)來合同第8版修改版,卻說不清改了哪里
導師在論文修改稿里標注了十幾處調整,需要逐一核對
團隊協(xié)作文檔頻繁更新,版本差異讓人眼花繚亂
傳統(tǒng)的手動比對不僅效率低下,還容易遺漏關鍵修改。今天,我將揭秘如何用30行Node.js代碼,打造一個智能Word文檔差異比對工具,實現:
- 自動識別文本差異
- 智能標注修改痕跡
- 生成專業(yè)比對報告
一、安裝所需依賴
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庫創(chuàng)建新的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中的段落和文本節(jié)點,拼接成純文本字符串
*/
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. 為不同差異類型創(chuàng)建不同樣式的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);
// 如果不是最后一行,創(chuàng)建新段落
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');
// 執(zhí)行比較
compareWordFiles(file1, file2, output);
2、關鍵技術原理詳解
Word文檔解析:
mammoth庫解析.docx文件(實際是ZIP壓縮包),提取其中的document.xml文件內容- 解析XML結構,提取所有文本節(jié)點,忽略格式、圖片等非文本元素
差異比較算法:
diff庫使用Myers差分算法找出兩個文本序列的最長公共子序列(LCS)diffWords方法進行單詞級別的比較,比字符級比較更符合文檔比較的需求
Word文檔生成:
docx庫構建符合Office Open XML標準的Word文檔結構- 文檔結構包含段落(Paragraph)、文本塊(TextRun)等元素
- 顏色使用16進制RGB格式表示(如
1800a1表示藍色)
差異可視化:
- 新增內容用藍色加粗顯示,便于識別添加的內容
- 刪除內容用紅色刪除線顯示,表示已移除的內容
- 保留原始文本的段落結構,確保可讀性
文件處理:
- 最終生成的.docx文件實際上是包含多個XML文件的ZIP壓縮包
Packer.toBuffer方法將內存中的文檔結構打包成符合標準的.docx文件
結語:讓機器做枯燥的事,讓人做有創(chuàng)意的事
通過這個項目,我們不僅實現了一個實用的文檔比對工具,更演示了如何:
- 組合現有工具解決實際問題
- 用少量代碼創(chuàng)造高價值產出
- 將復雜技術轉化為簡單接口
下次當同事還在用"Ctrl+F"艱難找不同時,你可以優(yōu)雅地說:“試試我的智能比對工具?”
到此這篇關于使用Node.js實現Word文檔差異比較并高亮標注工具的文章就介紹到這了,更多相關Node.js Word差異比較并標注內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
npm?does?not?support?Node.js問題的解決辦法
這篇文章主要給大家介紹了關于npm?does?not?support?Node.js問題的解決辦法,文中通過代碼以及圖文介紹的非常詳細,對大家的學習或者工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-10-10
前端自動化開發(fā)之Node.js的環(huán)境搭建教程
這篇文章主要介紹了前端自動化開發(fā)之Node.js環(huán)境搭建的相關資料,文中介紹的非常詳細,對大家學習或者使用node.js具有一定的參考價值,需要的朋友們下面來一起看看吧。2017-04-04
win系統(tǒng)下nodejs環(huán)境安裝配置
這篇文章主要介紹了win系統(tǒng)下nodejs環(huán)境安裝配置的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-05-05
npm dose not support Node.js v10.15
這篇文章主要給大家介紹了關npm dose not support Node.js v10.15.3的解決方法,文中通過圖文介紹的非常詳細,對大家的學習或者工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-11-11
Node.js數據流Stream之Duplex流和Transform流用法
這篇文章介紹了Node.js數據流Stream之Duplex流和Transform流的用法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-07-07
基于node打包可執(zhí)行文件工具_Pkg使用心得分享
下面小編就為大家分享一篇基于node打包可執(zhí)行文件工具_Pkg使用心得分享,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01

