JavaScript diff-match-patch库数字差异对比异常问题求助
解决方案:让diff-match-patch将数字作为整体对比
核心思路
diff-match-patch默认的逐字符对比逻辑会拆分数字,要解决这个问题,需要先将文本按「数字/非数字」分割为独立token,让库基于token级对比,再将结果转换回原文本格式。这样数字会被当作一个整体处理,不会被拆分。
具体实现
1. 工具函数:分割与拼接token
先实现两个辅助函数,用于将文本拆分为数字/非数字token,以及用特殊分隔符拼接token(避免与原文本内容冲突):
// 分割文本为数字、非数字独立token function tokenize(text) { // 正则(\d+)会捕获连续数字,split后保留数字和非数字片段,filter过滤空字符串 return text.split(/(\d+)/).filter(token => token.length > 0); } // 用不可见控制字符拼接token,确保diff-match-patch将每个token视为整体 function joinTokens(tokens) { return tokens.join('\u0001'); // \u0001是不会出现在普通文本中的控制字符 }
2. 修改后的diff生成函数
基于原函数改造,加入token预处理和后处理逻辑:
function generateDiff(text1, text2) { const dmp = new diff_match_patch(); // 预处理:将原始文本转换为token拼接的特殊字符串 const tokens1 = tokenize(text1); const tokens2 = tokenize(text2); const tokenText1 = joinTokens(tokens1); const tokenText2 = joinTokens(tokens2); // 基于token文本生成diff(此时每个token被视为一个"字符") let diff = dmp.diff_main(tokenText1, tokenText2); dmp.diff_cleanupSemantic(diff); let display1 = ''; let display2 = ''; // 遍历diff结果,将token拆回原始内容并生成显示元素 for (const [op, data] of diff) { const tokens = data.split('\u0001').filter(t => t); for (const token of tokens) { const span1 = document.createElement('span'); const span2 = document.createElement('span'); if (op === 0) { // 内容相同 span1.className = 'diff-equal'; span2.className = 'diff-equal'; span1.textContent = token; span2.textContent = token; display1 += span1.outerHTML; display2 += span2.outerHTML; } else if (op === -1) { // 原文本删除内容 span1.className = 'diff-delete'; span1.textContent = token; display1 += span1.outerHTML; } else { // 新文本新增内容 span2.className = 'diff-insert'; span2.textContent = token; display2 += span2.outerHTML; } } } return [display1, display2]; }
原理说明
- 预处理阶段:把"1657"和"2160"分别作为独立token,拼接后的字符串让diff-match-patch直接对比整个token,不会拆分字符
- diff阶段:库会识别到两个数字token完全不同,标记为「删除原数字+插入新数字」
- 后处理阶段:将token拆回原始内容,生成对应的高亮span,实现你期望的整体数字对比效果
内容的提问来源于stack exchange,提问作者efebeydogan
相关产品推荐
相关产品推荐

