我尝试将Google diff-match-path库用于行差异: https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs。总而言之,两个输入的行都超过65,536(2 ^ 16)行,我得到了错误的补丁。
是一个错误(在我的代码或diff-match-patch中),还是我遇到了javascript / nodejs的已知限制?我可以对较大的文件使用d-m-p吗?
使用node version v6.3.1, diff-match-patch 1.0.4
此脚本重现了问题
var diff_match_patch = require("diff-match-patch")
// function copied from google wiki
// https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
function diff_lineMode(text1, text2) {
var dmp = new diff_match_patch();
var a = dmp.diff_linesToChars_(text1, text2);
var lineText1 = a.chars1;
var lineText2 = a.chars2;
var lineArray = a.lineArray;
var diffs = dmp.diff_main(lineText1, lineText2, false);
dmp.diff_charsToLines_(diffs, lineArray);
return diffs;
}
// reproduce problem by diffing string with many lines to "abcd"
for (let size = 65534; size < 65538; size += 1) {
let text1 = "";
for (let i = 0; i < size; i++) {
text1 += i + "\n";
}
var patches = diff_lineMode(text1, "abcb")
console.log("######## Size: " + size + ": patches " + patches.length)
for (let i = 0; i < patches.length; i++) {
// patch[0] is action, patch[1] is value
var action = patches[i][0] < 0 ? "remove" : (patches[i][0] > 0 ? "add" : "keep")
console.log("patch" + i + ": " + action + "\n" + patches[i][1].substring(0, 10))
}
}
提供这些输出:
######## Size: 65534: patches 2
patch0: remove
0
1
2
3
4
patch1: add
abcb
######## Size: 65535: patches 2
patch0: remove
0
1
2
3
4
patch1: add
######## Size: 65536: patches 2
patch0: keep
0
patch1: remove
1
2
3
4
5
######## Size: 65537: patches 3
patch0: remove
0
patch1: keep
1
patch2: remove
2
3
4
5
6
答案 0 :(得分:2)
这是ES5和算法映射行到16位unicode字符的限制。在ES6上,它可以扩展为2 ^ 21位,从而覆盖更长的文件。
为了加快行间差异,该算法不比较整个文本,而是用单个unicode字符替换每行。因此,替换中的每个字符都映射到哈希图中的唯一行。但是unicode字符的数量是有限的,并且当前的实现只是溢出。
这不会导致误报(相同的行仍被认为是相同的),但是对于自然差异,它可能会以每行1 / 65K的低概率错过某些行差异。
并且由于不同的行被映射到同一字符,因此它阻止了补丁可靠地映射回原始文本行,因此逆过程将所有此类字符映射到第一条映射行。
通过使用较大的符号目标空间(例如使用2或3个字符表示唯一的行),应该有可能将正确的差异缩放到更大的输入。