Skip to content

Instantly share code, notes, and snippets.

@Szandor72
Created July 14, 2017 12:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Szandor72/56b0966e8e6a712335904ce048848359 to your computer and use it in GitHub Desktop.
Save Szandor72/56b0966e8e6a712335904ce048848359 to your computer and use it in GitHub Desktop.
diff javascript
Array.prototype.rotate = function(n){
var len = this.length,
res = new Array(this.length);
if (n % len === 0) return this.slice();
else for (var i = 0; i < len; i++) res[i] = this[(i + (len + n % len)) % len];
return res;
};
String.prototype.diff = function(s,p){ // p -> precision factor
function getMatchingSubstring(s,l,m){ // returns the first matching substring in-between the two strings
var i = 0,
slen = s.length,
match = false,
o = {fis:slen, mtc:m, sbs:""}; // temporary object used to construct the cd (change data) object
while (i < slen ) {
l[i] === s[i] ? match ? o.sbs += s[i] // o.sbs holds the matching substring itsef
: (match = true, o.fis = i, o.sbs = s[i])
: match && (i = slen); // stop after the first found substring
++i;
}
return o;
}
function getChanges(t,s,m){
var isThisLonger = t.length >= s.length ? true : false,
[longer,shorter] = isThisLonger ? [t,s] : [s,t], // assignment of longer and shorter by es6 destructuring
bi = 0; // base index designating the index of first mismacthing character in both strings
while (shorter[bi] === longer[bi] && bi < shorter.length) ++bi; // make bi the index of first mismatching character
longer = longer.split("").slice(bi); // as the longer string will be rotated it is converted into array
shorter = shorter.slice(bi); // shorter and longer now starts from the first mismatching character
var len = longer.length, // length of the longer string
cd = {fis: shorter.length, // the index of matching string in the shorter string
fil: len, // the index of matching string in the longer string
sbs: "", // the matching substring itself
mtc: m + s.slice(0,bi)}, // if exists mtc holds the matching string at the front
sub = {sbs:""}; // returned substring per 1 character rotation of the longer string
if (shorter !== "") {
for (var rc = 0; rc < len && sub.sbs.length < p; rc++){ // rc -> rotate count, p -> precision factor
sub = getMatchingSubstring(shorter, longer.rotate(rc), cd.mtc); // rotate longer string 1 char and get substring
sub.fil = rc < len - sub.fis ? sub.fis + rc // mismatch is longer than the mismatch in short
: sub.fis - len + rc; // mismatch is shorter than the mismatch in short
sub.sbs.length > cd.sbs.length && (cd = sub); // only keep the one with the longest substring.
}
}
// insert the mismatching delete subsrt and insert substr to the cd object and attach the previous substring
[cd.del, cd.ins] = isThisLonger ? [longer.slice(0,cd.fil).join(""), shorter.slice(0,cd.fis)]
: [shorter.slice(0,cd.fis), longer.slice(0,cd.fil).join("")];
return cd.del.indexOf(" ") == -1 ||
cd.ins.indexOf(" ") == -1 ||
cd.del === "" ||
cd.ins === "" ||
cd.sbs === "" ? cd : getChanges(cd.del, cd.ins, cd.mtc);
}
var changeData = getChanges(this,s,""),
nextS = s.slice(changeData.mtc.length + changeData.ins.length + changeData.sbs.length), // remaining part of "s"
nextThis = this.slice(changeData.mtc.length + changeData.del.length + changeData.sbs.length), // remaining part of "this"
result = ""; // the glorious result
changeData.del.length > 0 && (changeData.del = '<span class = "deleted">' + changeData.del + '</span>');
changeData.ins.length > 0 && (changeData.ins = '<span class = "inserted">' + changeData.ins + '</span>');
result = changeData.mtc + changeData.del + changeData.ins + changeData.sbs;
result += (nextThis !== "" || nextS !== "") ? nextThis.diff(nextS,p) : "";
return result;
};
textOld.oninput = function(e){textNew.innerText = this.value};
textNew.onfocus = function(e){this.select()};
myButton.onclick = function(e){
var sr = "",
so = textOld.value,
sn = textNew.value,
ts = 0,
te = 0;
ts = performance.now();
sr = so.diff(sn,+precision.value);
te = performance.now();
textdiff.innerHTML = sr;
perfdiff.textContent = "Diffing the above texts took " + (te-ts) + "msecs";
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment