javascript模拟git diff命令实现文本文件差异比较
作者:狄龙疤
这篇文章主要为大家详细介绍了javascript如何模拟git diff命令实现文本文件差异比较效果,文中的示例代码讲解详细,感兴趣的小伙伴可以参考下
diff.html:
<!DOCTYPE html> <html> <head> <title>文件比较</title> <meta charset="UTF-8"> </head> <body> <h1>文件比较</h1> <form> <label for="file1">版本1:</label> <input type="file" id="file1" name="file1"><br><br> <label for="file2">版本2:</label> <input type="file" id="file2" name="file2"><br><br> <button type="button" onclick="compare()">开始比较</button> </form> <div id = "div_info" style="width:1000px;height:500px;border:1px solid gray;overflow:auto"> </div> <script> var infoDiv = document.getElementById("div_info"); function compare() { var file1 = document.getElementById("file1").files[0]; var file2 = document.getElementById("file2").files[0]; var reader1 = new FileReader(); var reader2 = new FileReader(); reader1.readAsText(file1); reader2.readAsText(file2); var lines_v1 = null; var lines_v2 = null; reader1.onload = function() { lines_v1 = reader1.result.split('\n'); // printArray( lines_v1 ); reader2.onload = function() { lines_v2 = reader2.result.split('\n'); // printArray( lines_v2 ); // 比较两个文档的区别 docDiff( lines_v1,lines_v2 ); } } } function printArray( array ){ var len = array.length; for (let i = 0; i < len; i++){ console.log( "[" + array[ i ] + "]" ); } } function docDiff( lines_v1,lines_v2 ){ var dp = calculateShortestEditDistance(lines_v1, lines_v2); var index1 = lines_v1.length - 1; var index2 = lines_v2.length - 1; console.log("一共需要" + dp[ index1 ][ index2 ] + "步编辑操作"); var results = []; while ( index1 >= 0 && index2 >= 0 ){ var line_v1 = lines_v1[ index1 ]; var line_v2 = lines_v2[ index2 ]; if( line_v1 == line_v2 ){ // v1:...a // v2:...a // 原封不动的输出 results.push( " " + line_v1 ); index1--; index2--; }else { // v1:...a // v2:...b // v1:... a // v2:... b // 此时,a修改修改为b var sed1 = 0; if( index1 > 0 && index2 >0 ){ sed1 = dp[index1 - 1][index2 - 1]; } // v1:...a // v2: ... b // 此时,需要插入b var sed2 = 0; if( index2 >0 ){ sed2 = dp[index1][index2 - 1]; } // v1: ... a // v2:...b // 此时,需要删除a var sed3 = 0; if( index1 > 0 ){ sed3 = dp[index1-1][index2]; } var sed = Math.min( sed1,sed2,sed3 ); if( sed == sed1 ){ // results.add( "edit " + line_v2 + " DIFF:" + StringDiffTest.diff( line_v1,line_v2 ) ); // var diffInfo = StringDiffTest.diff(line_v1, line_v2); // results.add( "edit " + diffInfo ); results.push( "- " + line_v1 ); results.push( "+ " + line_v2 ); index1--; index2--; }else if( sed == sed2 ){ results.push( "+ " + line_v2 ); index2--; }else if( sed == sed3 ){ results.push( "- " + line_v1 ); index1--; } } } while ( index1 >= 0 ){ // v1 中多出的 "首行们" 都是需要删除的 results.push( "- " + lines_v1[ index1 ] ); index1--; } while ( index2 >= 0 ){ // v2 中多出的 "首行们" 都是需要被插入的 results.push( "+ " + lines_v2[ index2 ] ); index2--; } for ( var i=results.length -1;i>=0;i-- ){ var line = results[ i ]; var small = document.createElement( "small" ); small.innerHTML = line; if( line.startsWith( "-" ) ){ small.style.color = "red"; }else if( line.startsWith( "+" ) ){ small.style.color = "green"; } infoDiv.appendChild( small ); infoDiv.appendChild( document.createElement( "br" ) ); } } // 返回 int[][] function calculateShortestEditDistance( lines_v1,lines_v2 ){ // dp[i][j] 表示的是将 lines_v1 的前i个元素变换为 lines_v2 中的前j个元素需要使用的最优( 即需要转换步骤最少 )的转换方式 var size_v1 = lines_v1.length; var size_v2 = lines_v2.length; var dp = createArray( size_v1,size_v2 ); for (var index1 = 0; index1 < size_v1; index1++) { var line_v1 = lines_v1[ index1 ]; for (var index2 = 0; index2 < size_v2; index2++) { var line_v2 = lines_v2[ index2 ]; if( index1 == 0 ){ if( index2 == 0 ){ if( line_v1 == line_v2 ){ // v1:a // v2:a dp[ index1 ][ index2 ] = 0; }else { // v1:a // v2:b dp[ index1 ][ index2 ] = 1; } }else { if( contains( lines_v2,line_v1,0,index2 ) ){ // v1: a // v2:...a... size = index2 + 1 // v1转换为 v2需要 size - 1步( 也就是 index2步 )插入操作 dp[ index1 ][ index2 ] = index2; }else { // v1: a // v2:...b... size = index2 + 1 // v1转换为 v2需要 1步编辑操作,size-1= index2 步插入操作,一共index2 + 1步操作 dp[ index1 ][ index2 ] = index2 + 1; } } }else { if( index2 == 0 ){ if( contains(lines_v1, line_v2, 0, index1) ){ // v1:....a... size = index1 + 1 // v2: a // v1转换为 v2需要 size-1=index1步删除操作 dp[ index1 ][ index2 ] = index1; }else { // v1:....a... size = index1 + 1 // v2: b // v1转换为 v2需要 1步编辑操作和size-1=index1步删除操作,一共index1+1步操作 dp[ index1 ][ index2 ] = index1 + 1; } }else { if( line_v1 == line_v2 ){ // v1:...a // v2:...a dp[ index1 ][ index2 ] = dp[ index1 - 1 ][ index2 - 1 ]; }else { // v1:...a // v2:...b // v1:... a // v2:... b // 此时 v1 的前部分和 v2的前部分做dp运算,a修改为b var sed_prev1 = dp[ index1 - 1 ][ index2 - 1 ]; // v1: ... a // v2:...b // 此时v1的前部分和v2做dp运算,删除a var sed_prev2 = dp[ index1 - 1 ][ index2 ]; // v1: ...a // v2: ... b // 此时 v1和v2的前部分做dp运算,插入b var sed_prev3 = dp[ index1 ][ index2 - 1 ]; dp[ index1 ][ index2 ] = Math.min( sed_prev1,sed_prev2,sed_prev3 ) + 1; } } } } } return dp; } // todo 测试行列是否写反了 function createArray(rowCount, colCount) { var arr = []; for (var i = 0; i < rowCount; i++) { arr[i] = []; for (var j = 0; j < colCount; j++) { arr[i][j] = 0; } } return arr; } function contains(lines, targetLine, beginIndex, endIndex) { for (var i = beginIndex; i <=endIndex ; i++) { if( lines[ i ] == targetLine ){ return true; } } return false; } </script> </body> </html>
doc_v1.txt:
盼望着,盼望着,东风来了,春天的脚步近了。 一切都像刚睡醒的样子,欣欣然张开了眼。 山朗润起来了,水涨起来了,太阳的脸红起来了。 小草偷偷地从土地里钻出来,嫩嫩的,绿绿的。 园子里,田野里,瞧去,一大片一大片满是的。 坐着,躺着,打两个滚,踢几脚球,赛几趟跑,捉几回迷藏。 风轻俏俏的,草软绵绵的。 桃树,杏树,梨树,你不让我,我不让你,都开满了花赶趟儿。 红的像火,粉的像霞,白的像雪。 花里带着甜味;闭了眼,树上仿佛已经满是桃儿,杏儿,梨儿。 花下成千成百的蜜蜂嗡嗡的闹着,大小的蝴蝶飞来飞去。 野花遍地是:杂样儿,有名字的,没名字的,散在草丛里像眼睛像星星,还眨呀眨。 “吹面不寒杨柳风”,不错的,像母亲的手抚摸着你,风里带着些心翻的泥土的气息,混着青草味儿,还有各种花的香,都在微微润湿的空气里酝酿。 鸟儿将巢安在繁花嫩叶当中,高兴起来,呼朋引伴的卖弄清脆的歌喉,唱出婉转的曲子,跟清风流水应和着。 牛背上牧童的短笛,这时候也成天嘹亮的响着。 雨是最寻常的,一下就是三两天。 可别恼。看,像牛牦,像花针,像细丝,密密的斜织着,人家屋顶上全笼着一层薄烟。 树叶却绿得发亮,小草也青得逼你的眼。傍晚时候,上灯了,一点点黄晕的光,烘托出一片安静而和平的夜。 在乡下,小路上,石桥边,有撑着伞慢慢走着的人,地里还有工作的农民,披着所戴着笠。 他们的房屋稀稀疏疏的,在雨里静默着。 天上的风筝渐渐多了,地上的孩子也多了。 城里乡下,家家户户,老老小小,也赶趟似的,一个个都出来了。 舒活舒活筋骨,抖擞抖擞精神,各做各的一份事儿去。 “一年之计在于春”,刚起头儿,有的是功夫,有的是希望 春天像刚落地的娃娃,从头到脚都是新的,它生长着。 春天像小姑娘,花枝招展的笑着走着。 春天像健壮的青年,有铁一般的胳膊和腰脚,领着我们向前去。
doc_v2.txt:
盼望着,盼望着,东风来了,春天的脚步进了。 一切都像刚睡醒的样子,欣欣然张开了眼。 山朗润起来了,水涨起来了,太阳的脸红起来了。 小草偷偷地从土地里钻出来,嫩嫩的,绿绿的。 园子里,田野里,瞧去,一大片一大片满是的。 坐着,躺着,打两个滚、踢几脚球,赛几趟跑、捉几回迷藏。 风轻巧巧的,草软绵绵的。 桃树,杏树,梨树,你不让我,我不让你,都开满了花赶趟儿。 红的像火,粉的像霞,白的像雪。 花里带着甜味;闭了眼,树上仿佛已经满是桃儿,杏儿,梨儿。 花下成千成百的蜜蜂嗡嗡的闹着,大小的蝴蝶非来非去。 野花遍地是:杂样儿,有名字的,没名字的,散在草丛里像眼睛像星星,还眨呀眨。 “吹面不寒杨柳风”,不错的,像母亲的手抚摸着你,风里带着些心翻的泥土的气息,混着青草味儿,还有各种花的香,都在微微润湿的空气里酝酿。 鸟儿将巢安在繁花嫩叶当中,高兴起来,呼朋引伴的卖弄风骚清脆的歌喉,唱出婉转的曲子,跟清风流水应和着。 牛背上牧童的断敌,这时候也成天嘹亮的响着。 雨是最寻常的,一下就是三两天。 可别恼。看,像牛牦,像花针,象细丝,密密的斜织着,人家屋顶上全笼着亿层薄烟。 树叶却绿得发亮,小草也青得逼你的眼。傍晚时候,上灯了,一点点黄晕的光,烘托出一片安静而和平的夜。 在乡下,小路上,石桥边,有撑着伞慢慢走着的人,地里还有工作的农民,披星戴月着所戴着笠。 他们的房屋稀稀疏疏的,在雨里静默着。 天上的风筝渐渐多了,地上的孩子也多了。 城里乡下,家家户户,老老小小,也赶趟似的,一各各都出来了。 舒活舒活筋骨,抖擞抖擞精神,各做各的一份事儿去。 "一年之计在于春",刚起头儿,有的是功夫,有的是希望 春天刚落地的娃娃,从头到脚都是,它生长着。 春天像小菇娘,花枝招展的笑着走着。 春天像键壮的青年,有铁一般的胳膊和腰脚,领着我们向前去。
测试效果:
以上就是javascript模拟git diff命令实现文本文件差异比较的详细内容,更多关于javascript文本比较的资料请关注脚本之家其它相关文章!