实习技术总结(二)JS Diff

635 阅读2分钟

JS Diff 文本差分

最近在项目的开发过程中遇到了需要对比两个单词并且加粗显示diff字母的业务场景,我使用了一个好用且经典的js库 diff 来完成。

image.png

库简介

diff是一个基于javascript实现的文本内容diff的库。它基于已发表论文中的算法An O(ND) Difference Algorithm and its Variations" (Myers, 1986).

安装

npm install diff --save

引用

//  不支持import 语法,也就是module引入
const jsDiff = require('diff');

API

JsDiff.diffChars(oldStr, newStr[, options]) 将比较两段文字,比较的维度是基于单个字符,返回一个由描述改变的对象组成的array,再通过遍历对array中的每一个对象进行我们希望的操作(加粗显示、颜色区分等)。例如,要比较的两个单词为woraswords,diffChars返回的array为:

[ 
    { "count": 3, "value": "wor" },
    { "count": 1, "removed": true, "value": "a" },
    { "count": 1, "added": true, "value": "d" },
    { "count": 1, "value": "s" } 
]
  • added表示是否是添加内容,removed表示是否为删除内容。共有的内容这两个属性都没有,value表示内容,count表示字符的个数。
  • 可选的配置属性ignoreCase: 标记为true时忽略字符的大小写,默认为false。

项目示例(Vue版)

diff.js

function StringBuffer() {
  this.strings = [];
}
StringBuffer.prototype.append = function (str) {
  this.strings.push(str);
  return this;
};
StringBuffer.prototype.appendFormat = function (str) {
  this.strings.push(str);
  return this;
};
StringBuffer.prototype.toString = function () {
  return this.strings.join('');
};
StringBuffer.prototype.clear = function () {
  this.strings = [];
};
StringBuffer.prototype.size = function () {
  return this.strings.length;
};
//  引入diff库
const Diff = require('diff');

const formatDiffLetter = (oldStr, str) => {
  const diff = Diff.diffChars(oldStr, str);
  //  console.log(diff)
  const result = new StringBuffer();
  diff.forEach((part) => {
    if (part.added) {
      result.append("<span class='strong-letter'>");
      result.append(part.value);
      result.append('</span>');
    } else if (!part.removed) {
      result.append("<span class='normal-letter'>");
      result.append(part.value);
      result.append('</span>');
    }
  });
  return result;
};
export default formatDiffLetter;

error.vue

<template>
  ...
  <div v-html="formatDiffLetter(itemData.orgChunk, itemData.correctChunk)" />
  ...
</template>

<script>
import formatDiffLetter from './diff.js';
export default {
 ...
  methods: {
    formatDiffLetter,
  },
 ...
</script>

<style scoped>
  ::v-deep .strong-letter {
    font-weight: 600;
    font-size: 20px;
    color: rgba(255, 255, 255, 1);
  }
  ::v-deep .normal-letter {
    font-weight: 500;
    font-size: 18px;
    color: rgba(255, 255, 255, 0.9);
  }
</style>

应用说明

候选词与原词 diff 字母加粗,有以下三种简单场景:

  1. Change:候选词与原词同位置的某字母不同,替换后的字母加粗

image.png

  1. Add:候选词增加字母,新增的字母加粗

image.png

  1. Remove:候选词较与原词删除字母,无法diff,无加粗

image.png

更多复杂场景可由以上三种简单场景组合衍生,例如:

  1. Add + Change:新增字母 s 加粗,替换字母 a 加粗

image.png

  1. Remove + Change :删除字母 s 不加粗,替换字母 a 加粗

image.png

  1. Remove + Add :删除字母 e 不加粗,新增字母 c 加粗 image.png

参考