js文本比较(json数据比较)

最近有个需求要求比较json数据,当然有最简单的方法,循环每个键来比值,但是我偏不!因为正好想趁这个机会写一个文本比较的工具(类似git自带的比较),我搜了一下网络只找到一个LD算法似乎可以用,自己写了个demo效率一般把,而且感觉好复杂太高深。所以还是以我的理解写了一个比较工具。

水平有限所以我不会写很高深的东西,所以尽量往简单的地方靠。基本概念,就是先把文本分段(比如5行一段),然后在这5行里找一个连续最多的行做基准(文本差异度>60的认为是新增行,其他的是编辑行),向下连续查找。简单的说就是尽量把能连续对上的作为基准,一路往下对。

这里提一下,如果希望比对的更精确,可以把findLen设置的大一点,比如设置成left或right里比较大的行数,这样比对起来会避免一些问题,如:当中隔了很多行(>findLen)才是正确的行,导致检索默认5行没找到,就认为是新增行了。当然这样每条比的数量就多了也就慢了自己把握。

function compare(){
    this.findLen = 5, // 查块大小,如果你希望更准确可以把这个值改大一点比如50行
    this.jsonSort = function (obj) {
        let names = [];
        let newObj = {};

        if (Array.isArray(obj)) {
            let list = [];
            for (let i=0;i<obj.length;i++) {
                list.push(this.jsonSort(obj[i]));
            }
            list.sort();
            return list;
        } else {
            for (let o in obj) {
                names.push(o);
            }
            names.sort();
            for (let i=0;i<names.length;i++) {
                let n = names[i];
                if ("function" != typeof obj[n]) {
                    if ("object" == typeof obj[n]) {
                        if (obj[n]) {
                            newObj[n] = this.jsonSort(obj[n]);
                        }
                    } else {
                        newObj[n] = obj[n];
                    }
                }
            }
        }

        return newObj;
    },
    this.json2Lines = function (obj) {
        let jsonVal = JSON.stringify(obj, null, '\t');
        let lines = [];
        let lineStr = "";
        console.log(jsonVal);
        for (let i=0;i<jsonVal.length; i++) {
            if ('\t' == jsonVal.charAt(i) || '\n' == jsonVal.charAt(i)) {
                let s = lineStr.trim();
                if (s.length > 0) {
                    lines.push(lineStr.trim());
                }
                lineStr = "";
            } else {
                lineStr += jsonVal.charAt(i);
            }
        }

        lines.push(lineStr);
        return lines;
    },
    this.difference = function (leftStr, rightStr) {
        let count = 0, tmpCount = 0;
        for (let i=0;i<leftStr.length && i < rightStr.length;i++) {
            if (leftStr.charAt(i) == rightStr.charAt(i)) {
                tmpCount++;
            } else {
                count += tmpCount;
                tmpCount = 0;
            }
        }

        if (tmpCount > 0) {
            count+=tmpCount;
        }

        return count / Math.max(leftStr.length, rightStr.length) * 100;
    },
    this.compareFind = function (index, start, left, right) {
        let val = {
            right: start,
            series: 0,
            find: false
        };
        if (index < left.length && start < right.length) {
            let score = this.difference(left[index], right[start]);
            if (score > 60) {
                let rtn = this.compareFind(index + 1, start + 1, left ,right);
                val.find = true;
                val.series += rtn.series + 1;
            }
        }

        return val;
    },
    this.compareNext = function (s1, s2, left, right, result) {
        let diff = {
            left: 0,
            series: 0,
            right: 0,
            find: false
        };
        for (let i=s1; i - s1 < this.findLen && i< left.length; i++) {
            let len = this.compareFind(i, s2, left, right);
            if (diff.series < len.series) {
                diff.left = i;
                diff.series = len.series;
                diff.right = len.right;
            }
        }

        if (diff.series > 0) {
            for (let i=s1;i<diff.left;i++) {
                result[i] = "<span style='background-color: pink'>" + left[i] + "</span>"; // 标记新增的部分
            }

            let r = diff.right;
            for (let i=diff.left; i<diff.left + diff.series;i++) {
                let score = this.difference(left[i], right[r++]);
                if (score < 100) {
                    result[i] = "<span style='background-color: yellow'>" + left[i] + "</span>"; // 标记修改的部分
                } else {
                    result[i] = left[i]; // 相同的部分
                }
            }
            diff.find = true;
        } else {
          // result.push("<span style='background-color: pink'>" + left[s1] + "</span>"); // 标记新增的部分
          if (s2 + 1 < right.length) {
            let f = this.compareNext(s1, s2 + 1, left, right, result);
            return {
              series: f.series,
              left: f.left,
              right: f.right,
              find: f.find
            }
          } else {
            diff.left = s1 + 1;
            diff.right = s2;
          }
        }

        return {
            series: diff.series,
            left: diff.left + diff.series,
            right: diff.right + diff.series,
            find: diff.find
        };
    },
    this.compareJson = function (left, right) {
        let result = [];
        let liftLine = this.json2Lines(left);
        let rightLine = this.json2Lines(right);
        let lIndex = 0, rIndex = 0;
        while (lIndex < liftLine.length) {
            let diff = this.compareNext(lIndex, rIndex, liftLine, rightLine, result);
            if (!diff.find) {
                result[lIndex] = "<span style='background-color: pink'>" + left[lIndex] + "</span>"; // 标记新增的部分
            }
            lIndex = diff.left;
            rIndex = diff.right;
            // break;
        }

        return result;
    },
    this.jsonToCompare = function (left, right) {
        try {
            //json对象排序
            let l = this.jsonSort(JSON.parse(left));
            let r = this.jsonSort(JSON.parse(right));
            let res = this.compareJson(l, r);
            return res.join(" ");
        } catch (e) {}
        return left;
    }
}
//调用例子

    let json1= {
        v1: "abc",
        v2: "ccc",
        v3: "ddd",
        v4: "555"
    }, json2= {
        v1: "abc",
        v2: "ccc",
        v3: "eee"
    }
let cp = new compare();

cp.jsonToCompare(json1, json2);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值