Skip to content

Commit 81d02fb

Browse files
committed
init
1 parent 343911f commit 81d02fb

File tree

5 files changed

+238
-0
lines changed

5 files changed

+238
-0
lines changed

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,32 @@ diff-merge
22
==========
33

44
diff & merge algorithm realized with Javascript
5+
6+
## Usage
7+
8+
- nodejs
9+
10+
var _ = require('diff-merge'),
11+
compare = _.compare,
12+
merge = _.merge;
13+
14+
- browser
15+
16+
<script type="text/javascript" src="../lib/compare.js"></script>
17+
<script type="text/javascript" src="../lib/merge.js"></script>
18+
19+
## Compare
20+
21+
var s1 = 'a,bc',
22+
s2 = 'a,bcd',
23+
splitter = ',';
24+
25+
var compareResult = compare(s1, s2, splitter);
26+
27+
## merge
28+
29+
var s3 = merge(s1, compareResult);
30+
31+
## test
32+
33+
test/test.html

index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
compare: require('./lib/compare'),
3+
merge: require('./lib/merge')
4+
};

lib/compare.js

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
(function(global, undefined){
2+
3+
var compare = function(cnt1, cnt2, splitter){
4+
var SPLITTER = splitter || '',
5+
6+
MARK_EMPTY = -1,
7+
MARK_SAME = 0,
8+
9+
STEP_NOCHANGE = 0,
10+
STEP_REPLACE = 1,
11+
STEP_REMOVE = 2,
12+
STEP_INSERT = 3;
13+
14+
// result object
15+
var diff = [],
16+
result = {
17+
splitter: SPLITTER,
18+
diff: diff
19+
};
20+
21+
// if string equal
22+
if(cnt1 === cnt2){
23+
return result;
24+
}
25+
26+
// convert string to array
27+
var arr1 = cnt1.split(SPLITTER),
28+
arr2 = cnt2.split(SPLITTER);
29+
30+
// caculate min distance & log each step
31+
var l1 = arr1.length,
32+
l2 = arr2.length,
33+
dists = Array.apply(null, {length: l1 + 1}).map(function(){return [];}),
34+
steps = Array.apply(null, {length: l1 + 1}).map(function(){return [];}),
35+
i, j;
36+
37+
for(i = 0; i <= l1; i++){
38+
for(j = 0; j <= l2; j++){
39+
40+
if(i === 0 || j === 0){
41+
dists[i][j] = i || j;
42+
steps[i][j] = i > 0 ? STEP_REMOVE : STEP_INSERT;
43+
44+
}else{
45+
var equal = arr1[i-1] === arr2[j-1],
46+
47+
removeDist = dists[i-1][j] + 1,
48+
insertDist = dists[i][j-1] + 1,
49+
replaceDist = dists[i-1][j-1] + (equal ? 0 : 1),
50+
dist = Math.min(replaceDist, removeDist, insertDist);
51+
52+
dists[i][j] = dist;
53+
54+
switch(dist){
55+
56+
case replaceDist:
57+
steps[i][j] = equal ? STEP_NOCHANGE : STEP_REPLACE;
58+
break;
59+
60+
case removeDist:
61+
steps[i][j] = STEP_REMOVE;
62+
break;
63+
64+
case insertDist:
65+
steps[i][j] = STEP_INSERT;
66+
67+
}
68+
}
69+
}
70+
}
71+
72+
// get contrast arrays (src & target) by analyze step by step
73+
var src = [], target = [];
74+
75+
for(i = l1,j = l2; i > 0 || j > 0;){
76+
switch(steps[i][j]){
77+
78+
case STEP_NOCHANGE:
79+
src.unshift(arr1[i-1]);
80+
target.unshift(MARK_SAME);
81+
i -= 1;
82+
j -= 1;
83+
break;
84+
85+
case STEP_REPLACE:
86+
src.unshift(arr1[i-1]);
87+
target.unshift(arr2[j-1]);
88+
i -= 1;
89+
j -= 1;
90+
break;
91+
92+
case STEP_REMOVE:
93+
src.unshift(arr1[i-1]);
94+
target.unshift(MARK_EMPTY);
95+
i -= 1;
96+
j -= 0;
97+
break;
98+
99+
case STEP_INSERT:
100+
src.unshift(MARK_EMPTY);
101+
target.unshift(arr2[j-1]);
102+
i -= 0;
103+
j -= 1;
104+
break;
105+
106+
}
107+
}
108+
109+
// convert contrast arrays to diff array
110+
var l = target.length,
111+
start, len, to,
112+
notEmpty = function(s){return s !== MARK_EMPTY;};
113+
114+
for(i = l - 1; i >= 0;){
115+
// join continuous diffs
116+
for(j = i; target[j] !== MARK_SAME && j >= 0; j--){}
117+
118+
if(j < i){
119+
start = src.slice(0, j + 1).filter(notEmpty).length; // start pos of diffs (on src)
120+
len = src.slice(j + 1, i + 1).filter(notEmpty).length; // length should be replaced (on src)
121+
to = target.slice(j + 1, i + 1).filter(notEmpty).join(SPLITTER);// new content
122+
123+
diff.unshift([start, len, to]);
124+
}
125+
126+
i = j - 1;
127+
}
128+
129+
return result;
130+
};
131+
132+
if(typeof module === "object" && typeof module.exports === "object"){
133+
module.exports = compare;
134+
}else{
135+
global.compare = compare;
136+
}
137+
})(this);

lib/merge.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
(function(global, undefined){
2+
3+
var merge = function(cnt, compareResult){
4+
var splitter = compareResult.splitter,
5+
diff = compareResult.diff,
6+
result = cnt.split(splitter);
7+
8+
for(var i = diff.length - 1, item; i >= 0; i--){
9+
item = diff[i];
10+
result.splice(item[0], item[1], item[2]);
11+
}
12+
13+
return result.join(splitter);
14+
};
15+
16+
if(typeof module === "object" && typeof module.exports === "object"){
17+
module.exports = merge;
18+
}else{
19+
global.merge = merge;
20+
}
21+
})(this);

test/test.html

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title></title>
5+
<style type="text/css">
6+
textarea{
7+
height: 400px;
8+
width: 40%;
9+
}
10+
</style>
11+
</head>
12+
<body>
13+
14+
<textarea id="in1">
15+
if(i===0){for(e in t.par){t.pars.push([e,t.par[e]].join("="))}}else{for(e=0;e<i;e++){r=t.filter[e];t.pars.push([r,t.par[r]].join("="))}}t.pars=t.pars.join("&");window.jsQa=new Image(1,1);jsQa.src=t.url+t.pars;t.cookieSet(t.flag,t.hash(t.pars),0,"/",lib.SITE_DOMAIN);t.callback()}catch(o){return""}}};(function(){var t=new lib.action.Qa;try{t.init({url:window.location.protocol+"//msg.iqiyi.com/jpb.gif"})}catch(e){}})();(function(){var t=new lib.action.Qa;var e=t.cookieGet("QC001")=="1";var i=t.cookieGet("QC005");var r;if(e||!i||window.location.protocol=="https:"||lib.SITE_DOMAIN.match(/pps/)){return}t.cookieSet("QC001","1",24,"/",lib.SITE_DOMAIN);var o="324";var n={qiyi_cookie:i};var a={sid:i,p:"iqiyi"};var s="http://nsclick.baidu.com/v.gif",c=[],h="BD_QIYI_LOG_"+(new Date).getTime(),f=window[h]=new Image;c.push("pid="+o);for(r in n){c.push(r+"="+encodeURIComponent(n[r]))}f.src=s+"?"+c.join("&")+"&t="+(new Date).getTime();var u="http://cpro.baidu.com/cpro/ui/html/sync.htm",l=[],d="BD_QIYI_LOG_"+(new Date).getTime(),p=window[d]=new Image;for(r in a){l.push(r+"="+encodeURIComponent(a[r]))}p.src=u+"?"+l.join("&")+"&t="+(new Date).getTime()})();(function(){var t=function(){var t=2;var e=window.location.hostname.split(".");e=e.slice(e.length-t);return e.join(".")}();var e=t.match(/pps/);var i="http://msg.iqiyi.com/b?t=20&p=10&p1=101"+("&pf="+(e?"20":"")+"1");var r=function(t,e){t=t||{};if(e.indexOf("?")==-1){e+="?"}else{e+="&"}var i=+new Date;t._=i;for(var r in t){if(t.hasOwnProperty(r)){e+=encodeURIComponent(r)+"="+encodeURIComponent(t[r])+"&"}}if(e[e.length-1]==="&"){e=e.slice(0,-1)}var n=new Image;n.src=e};function n(){var t=[];var e="block-";var i,r,n,o;var a="A".charCodeAt();var s=function(t){return document.getElementById(t)};var c=String.fromCharCode;var u;for(u=0;u<26;u++){i=c(a+u);n=e+i;o=s(n);if(o){o["__bid__"]=i;t.push(o)}}for(u=0;u<26;u++){r=c(a+u);var h=false;for(var f=0;f<26;f++){i=c(a+f);n=e+r+i;o=s(n);if(o){h=true;o["__bid__"]=r+i;t.push(o)}}if(!h){break}}return t}function o(){var t=[];var e="block-";var i=document.getElementsByTagName("qchunk"),r,n;for(var o=0,a=i.length;o<a;o++){r=i[o];n=r.id||"";if(n.substr(0,e.length).toLowerCase()==e){r["__bid__"]=n.substr(e.length);t.push(r)}}return t}var a=function(t){t=t||window.event;var e=t.target||t.srcElement;var n=document.documentElement&&document.documentElement.scrollTop||document.body.scrollTop;var o=document.documentElement&&document.documentElement.scrollLeft||document.body.scrollLeft;var a=document.documentElement&&document.documentElement.scrollWidth||document.body.scrollWidth;var s=document.documentElement&&document.documentElement.scrollHeight||document.body.scrollHeight;var c=document.documentElement&&document.documentElement.clientHeight||document.body.clientHeight;var u=document.documentElement&&document.documentElement.clientWidth||document.body.clientWidth;var h=Math.max(s,c);var f=Math.max(a,u);var l=this["__bid__"]||"";var d=g(this.getAttribute("data-pb"),"&");var p,m,v;do{p=e;m=p.getAttribute("rseat");v=p.tagName.toUpperCase();e=e.parentNode;if(p==this){break}}while(!m&&v!=="A"&&v!=="IMG");var _=g(p.getAttribute("data-pb"),"&");var b,I,y;if(m){_.rseat=m}if(v==="A"){b=p.title||"";I="a";y=p.getAttribute("href")||""}else if(v==="IMG"){b=p.alt||"";I="i";y=""}else{b=p.title||"";I="e";y=""}var k,C,E;E=g(document.cookie,";");k=E["P00003"]||"";C=E["QC005"]||E["QC006"]||"";var M={block:l,rt:I,r:b,rlink:y,pu:decodeURIComponent(k),u:decodeURIComponent(C),re:f+"*"+h,clkx:t.clientX+o,clky:t.clientY+n};r(w(M,d,_),i)};var s=n();var c=o();var u,h;for(var f=0,l=s.length;f<l;f++){if(c.indexOf(s[f])==-1){c.push(s[f])}}if(c.length===0){u=document.getElementsByTagName("body")[0];h=a.bind(u);if(u.addEventListener){u.addEventListener("mousedown",h,false)}else{u.attachEvent("onmousedown",h)}}else{for(var d=0,p=c.length;d<p;d++){var m=c[d];var v=a.bind(m);if(m.addEventListener){m.addEventListener("mousedown",v,false)}else{m.attachEvent("onmousedown",v)}}}function g(t,e){var i={};e=e||"&";if(t){var r=t.split(e),n;for(var o=0,a=r.length;o<a;o++){n=r[o];if(n){n=n.split(/\s*=\s*/g);if(n[0]){i[n[0].replace(/^\s*|\s*$/g,"")]=n[1]||""}}}}return i}function w(t,e){var i=t||{};var r;for(var n=1,o=arguments.length;n<o;n++){r=arguments[n];if(r){for(var a in r){if(r.hasOwnProperty(a)){i[a]=r[a]}}}}return i}})();
16+
</textarea>
17+
18+
<textarea id="in2">
19+
if(i===0){for(e in t.par){t.pars.push([e,t.par[e]].join("="))}}else{for(e=0;e<i;e++){r=t.filter[e];t.pars.push([r,t.par[r]].join("="))}}t.pars=t.pars.join("&");window.jsQa=new Image(1,1);jsQa.src=t.url+t.pars;t.cookieSet(t.flag,t.hash(t.pars),0,"/",lib.SITE_DOMAIN);t.callback()}catch(o){return""}}};(function(){var t=new lib.action.Qa;try{t.init({url:window.location.protocol+"//msg.iqiyi.com/jpb.gif"})}catch(e){}})();(function(){var t=new lib.action.Qa;var e=t.cookieGet("QC001")=="1";var i=t.cookieGet("QC005");var r;if(e||!i||window.location.protocol=="https:"||lib.SITE_DOMAIN.match(/pps/)){return}t.cookieSet("QC001","1",2xxx4,"/",lib.SITE_DOMAIN);var o="324";var n={qiyi_cookie:i};var a={sid:i,p:"iqiyi"};var s="http://nsclick.baidu.com/v.gif",c=[],h="BD_QIYI_LOG_"+(new Date).getTime(),f=window[h]=new Image;c.push("pid="+o);for(r in n){c.push(r+"="+encodeURIComponent(n[r]))}f.src=s+"?"+c.join("&")+"&t="+(new Date).getTime();var u="http://cpro.baidu.com/cpro/ui/html/sync.htm",l=[],d="BD_QIYI_LOG_"+(new Date).getTime(),p=window[d]=new Image;for(r in a){l.push(r+"="+encodeURIComponent(a[r]))}p.src=u+"?"+l.join("&")+"&t="+(new Date).getTime()})();(function(){var t=function(){var t=2;var e=window.location.hostname.split(".");e=e.slice(e.length-t);return e.join(".")}();var e=t.match(/pps/);var i="http://msg.iqiyi.com/b?t=20&p=10&p1=101"+("&pf="+(e?"20":"")+"1");var r=function(t,e){t=t||{};if(e.indexOf("?")==-1){e+="?"}else{e+="&"}var i=+new Date;t._=i;for(var r in t){if(t.hasOwnProperty(r)){e+=encodeURIComponent(r)+"="+encodeURIComponent(t[r])+"&"}}if(e[e.length-1]==="&"){e=e.slice(0,-1)}var n=new Image;n.src=e};function n(){var t=[];var e="block-";var i,r,n,o;var a="A".charCodeAt();var s=function(t){return document.getElementById(t)};var c=String.fromCharCode;var u;for(u=0;u<26;u++){i=c(a+u);n=e+i;o=s(n);if(o){o["__bid__"]=i;t.push(o)}}for(u=0;u<26;u++){r=c(a+u);var h=false;for(var f=0;f<26;f++){i=c(a+f);n=e+r+i;o=s(n);if(o){h=true;o["__bid__"]=r+i;t.push(o)}}if(!h){break}}return t}function o(){var t=[];var e="block-";var i=document.getElementsByTagName("qchunk"),r,n;for(var o=0,a=i.length;o<a;o++){r=i[o];n=r.id||"";if(n.substr(0,e.length).toLowerCase()==e){r["__bid__"]=n.substr(exxx.length);t.push(r)}}return t}var a=function(t){t=t||window.event;var e=t.target||t.srcElement;var n=document.documentElement&&document.documentElement.scrollTop||document.body.scrollTop;var o=document.documentElement&&document.documentElement.scrollLeft||document.body.scrollLeft;var a=document.documentElement&&document.documentElement.scrollWidth||document.body.scrollWidth;var s=document.documentElement&&document.documentElement.scrollHeight||document.body.scrollHeight;var c=document.documentElement&&document.documentElement.clientHeight||document.body.clientHeight;var u=document.documentElement&&document.documentElement.clientWidth||document.body.clientWidth;var h=Math.max(s,c);var f=Math.max(a,u);var l=this["__bid__"]||"";var d=g(this.getAttribute("data-pb"),"&");var pxxx,m,v;do{p=e;m=p.getAttribute("rseat");v=p.tagName.toUpperCase();e=e.parentNode;if(p==this){break}}while(!m&&v!=="A"&&v!=="IMG");var _=g(p.getAttribute("data-pb"),"&");var b,I,y;if(m){_.rseat=m}if(v==="A"){b=p.title||"";I="a";y=p.getAttribute("href")||""}else if(v==="IMG"){b=p.alt||"";I="i";y=""}else{b=p.title||"";I="e";y=""}var k,C,E;E=g(document.cookie,";");k=E["P00003"]||"";C=E["QC005"]||E["QC006"]||"";var M={block:l,rt:I,r:b,rlink:y,pu:decodeURIComponent(k),u:decodeURIComponent(C),re:f+"*"+h,clkx:t.clientX+o,clky:t.clientY+n};r(w(M,d,_),i)};var s=n();var c=o();var u,h;for(var f=0,l=s.length;f<l;f++){if(c.indexOf(s[f])==-1){c.push(s[f])}}if(c.length===0){u=document.getElementsByTagName("boxxxdy")[0];h=a.bind(u);if(u.addEventListener){u.addEventListener("mousedown",h,false)}else{u.attachEvent("onmousedown",h)}}else{for(var d=0,p=c.length;d<p;d++){var m=c[d];var v=a.bind(m);if(m.addEventListener){m.addEventListener("mousedown",v,false)}else{m.attachEvent("onmousedown",v)}}}function g(t,e){var i={};e=e||"&";if(t){var r=t.split(e),n;for(var o=0,a=r.length;o<a;o++){n=r[o];if(n){n=n.split(/\s*=\s*/g);if(n[0]){i[n[0].replace(/^\s*|\s*$/g,"")]=n[1]||""}}}}return i}function w(t,e){var i=t||{};var r;for(var n=1,o=arguments.length;n<o;n++){r=arguments[n];if(r){for(var a in r){if(r.hasOwnProperty(a)){i[a]=r[a]}}}}return i}})();</textarea>
20+
21+
<script type="text/javascript" src="../lib/compare.js"></script>
22+
<script type="text/javascript" src="../lib/merge.js"></script>
23+
<script type="text/javascript">
24+
var test = function(s1, s2, splitter){
25+
var t = Date.now();
26+
27+
var compareResult = compare(s1, s2, splitter);
28+
29+
console.debug(Date.now() - t + ' ms');
30+
console.log(compareResult);
31+
32+
if(merge(s1, compareResult) !== s2){
33+
console.error('wrong');
34+
}else{
35+
console.info('ok');
36+
}
37+
};
38+
39+
var in1 = document.getElementById('in1'),
40+
in2 = document.getElementById('in2');
41+
42+
var doTest = function(){
43+
test(in1.value, in2.value, ',');
44+
};
45+
</script>
46+
</body>
47+
</html>

0 commit comments

Comments
 (0)