我使用 JavaScript 中的 diff-match-patch 库来确定和可视化某些组件的两个配置文件之间的差异。它通常工作得很好,但是我意识到,例如在一个文件的一行中有数字“1657”,而在另一个文件的相应行中有数字“2160”。在这种情况下,我希望它删除整个数字“1657”并将“2160”显示为全新的添加,但它只删除“57”并显示“2160”中的“2”和“0”作为新的补充。这就是 diff-match-patch 演示中的样子:
我理解这种行为是由于 diff-match-patch 算法的工作方式造成的,它只将“2”和“0”视为新添加,因为它们在前一个字符串中不存在 - 但我不知道如何修复它。我最初认为 diff-match-patch 不会进行逐个字符的比较,但演示页面表明它实际上会进行比较。
这是我使用 diff-match-patch 的函数的当前状态:
function generateDiff(text1, text2) {
let dmp = new diff_match_patch();
let diff = dmp.diff_main(text1, text2);
dmp.diff_cleanupSemantic(diff);
let display1 = '';
let display2 = '';
for (let i = 0; i < diff.length; i++) {
let part = diff[i];
let op = part[0]; // Operation (insert, delete, equal)
let data = part[1]; // Text of the change
let span1 = document.createElement('span');
let span2 = document.createElement('span');
if (op === 0) { // Equal
span1.className = 'diff-equal';
span2.className = 'diff-equal';
span1.textContent = data;
span2.textContent = data;
display1 += span1.outerHTML;
display2 += span2.outerHTML;
} else if (op === -1) { // Delete
span1.className = 'diff-delete';
span1.textContent = data;
display1 += span1.outerHTML;
} else { // Insert
span2.className = 'diff-insert';
span2.textContent = data;
display2 += span2.outerHTML;
}
}
return [display1, display2];
}
我尝试通过使用一些正则表达式并在文本中识别它们来仅以不同的方式处理数字,但它不起作用。我将不胜感激任何帮助,谢谢!
默认情况下,
diff-match-patch
基于字符(严格来说,基于UTF-16代码单元)创建差异。文档中的行或字差异文章解释了如何实现其他类型的差异:您需要将每个唯一的行/单词转换为唯一的字符,比较字符字符串,然后转换回来。
我创建了一个名为
diff-match-patch
的
diff-match-patch-unicode
分支,它本质上用一些方便的方法包装了库,默认使用 Unicode 代码点而不是 UTF-16 代码单元,并且还提供了一种自定义差异的简单方法通过 segmenter
选项设置粒度:
import { Differ, segmenters } from 'jsr:@clearlylocal/diff-match-patch-unicode'
const differ = new Differ()
const str1 = '1657\nTime: 0s'
const str2 = '2160\nTime: 0s'
// default options (diff by char, similar to the current behavior you're seeing)
differ.diff(str1, str2)
// [
// Diff #[ 1, "2" ],
// Diff #[ 0, "16" ],
// Diff #[ -1, "57" ],
// Diff #[ 1, "0" ],
// Diff #[ 0, "\nTime: 0s" ]
// ]
// passing word segmenter as an option (diff by word)
differ.diff(str1, str2, { segmenter: segmenters.word })
// [
// Diff #[ -1, "1657" ],
// Diff #[ 1, "2160" ],
// Diff #[ 0, "\nTime: 0s" ]
// ]
Differ#diff
方法和 SegmentCodec
类的相关部分,它们提供了必要的抽象。或者,您可以根据上面链接的 Line 或 Word Diffs 文档自行推出。
如果您决定自己动手,并假设单词是您要使用的单位,我强烈建议您使用
Intl.Segmenter
实例(例如 new Intl.Segmenter('en-US', { granularity: 'word' })
)来进行转换。