diff.js使用指南

前言

最近在開發(fā)過程中遇到了需要diff文件內(nèi)容或者大json的業(yè)務(wù)場景,發(fā)現(xiàn)了一個比較好用且經(jīng)典的js庫diff。這個庫功能十分強(qiáng)大,不僅能夠簡潔地輸出字符串結(jié)果,也能夠輸出規(guī)范化的數(shù)據(jù)結(jié)構(gòu)方便二次開發(fā)。這里筆者針對這個庫的文檔進(jìn)行翻譯和簡單的講解,同時也會展示自己的測試demo。

庫簡介

diff是一個基于javascript實(shí)現(xiàn)的文本內(nèi)容diff的庫。它基于已發(fā)表論文中的算法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]) 這個方法將比較兩段文字,比較的維度是基于單個字符
    返回一個由描述改變的對象組成的列表。大致如下:

    image

    added表示是否是添加內(nèi)容,removed表示是否為刪除內(nèi)容。共有的內(nèi)容這兩個屬性都沒有,value表示內(nèi)容,count表示字符的個數(shù)(在某些用法中表示內(nèi)容的行數(shù))
    可選的配置屬性ignoreCase: 標(biāo)記為true時忽略字符的大小寫,默認(rèn)為false,這里給出一個測試?yán)樱?br>
    image

    文中例子的線上演示地址演示地址

  • JsDiff.diffWords(oldStr, newStr[, options]) 該方法比較兩段文字,比較的維度是單詞,忽略空格,返回一個由描述改變對象組成的列表,可選的配置屬性ignoreCase: 同diffChars中一樣,這里給出一個使用例子:

    image

  • JsDiff.diffWordsWithSpace(oldStr, newStr[, options]) 該方法比較兩段文字,比較的維度是單詞,同上一個方法不同的是,它將比較空格的差異,返回一個由描述改變的對象組成的列表。這里給出一個例子:

    image

  • JsDiff.diffLines(oldStr, newStr[, options]) 比較兩段文字,比較的維度是行??蛇x的配置項(xiàng):
    ignoreWhitespace:設(shè)置為true時,將忽略開頭和結(jié)尾處的空格,在diffTrimmedLines中也有這個配置。
    newlineIsToken: 設(shè)置為true時,將換行符看作是分隔符。這樣就可以獨(dú)立于行內(nèi)容對換行結(jié)構(gòu)進(jìn)行更改,并將其視為獨(dú)立的(原文:This allows for changes to the newline structure to occur independently of the line content and to be treated as such, 這一句是機(jī)翻的,感覺不大準(zhǔn)確)??偟脕碚f,這樣使得diffLines的輸出對人類閱讀(相較于其他對計(jì)算機(jī)更為友好的輸出方式)更為友好,更加方便于比較差異。返回一個由描述改變的對象組成的列表。(這里返回的obj列表中,count表示這段內(nèi)容的行數(shù),下面的方法類似),接下來展示一個例子:

    image

  • sDiff.diffTrimmedLines(oldStr, newStr[, options]) 比較兩段文字,比較的維度是行,忽略開頭和結(jié)尾處的空格,返回一個由描述改變的對象組成的列表。實(shí)例截圖:

    image

  • JsDiff.diffSentences(oldStr, newStr[, options]) 比較兩段文字,比較的維度是句子。返回一個由描述改變的對象組成的列表。實(shí)例截圖:

    image

  • JsDiff.diffCss(oldStr, newStr[, options]) 比較兩段內(nèi)容,比較基于css中的相關(guān)符號和語法。返回一個由描述改變的對象組成的列表。

  • JsDiff.diffJson(oldObj, newObj[, options]) 比較兩個JSON對象,比較基于對象內(nèi)部的key。這些key在json對象內(nèi)的順序,在比較時將不會影響結(jié)果。返回一個由描述改變的對象組成的列表。展示一個例子:

    image

  • JsDiff.diffArrays(oldArr, newArr[, options]) 比較兩個數(shù)組,每一個元素使用嚴(yán)格等于來判定(===)??蛇x參數(shù):comparator: function(left, right)用來進(jìn)行相等性的比較,返回一個由描述改變的對象組成的列表。

  • JsDiff.createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader) -創(chuàng)造一個統(tǒng)一的diff補(bǔ)丁輸出。參數(shù):

    • oldFileName: 移除內(nèi)容在文件名部分輸出的字符串
    • newFileName: 增添內(nèi)容在文件名部分輸出的字符串
    • oldStr: 原始的字符串(作為基準(zhǔn))
    • newStr: 比較內(nèi)容的字符串
    • oldHeader: 在老文件頭部新增的信息
    • newHeader: 在新文件頭部新增的信息
    • options: 一個描述配置的對象,目前僅支持context,用來描述應(yīng)該展示context的多少行
      這里展示一個例子:
      image

      這里可以看到,該方法返回的是已經(jīng)格式化的可直接輸出的字符串,方便直接展示。
  • JsDiff.createPatch(fileName, oldStr, newStr, oldHeader, newHeader) -創(chuàng)造一個統(tǒng)一的diff補(bǔ)丁輸出,該方法的使用和JsDiff.createTwoFilesPatch幾乎一致,唯一的區(qū)別是oldFileName等于newFileName

  • JsDiff.structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) 返回一個由描述具體變化的對象構(gòu)成的數(shù)組。這個方法類似于createTwoFilesPatch,但是返回了一個適合于開發(fā)者后續(xù)處理的數(shù)據(jù)結(jié)構(gòu)。其參數(shù)跟createTwoFilesPatch保持一致,返回的數(shù)據(jù)類似于如下:

    image

    與之對應(yīng)的應(yīng)用實(shí)例如下:
    image

  • JsDiff.applyPatch(source, patch[, options]) 使用一個統(tǒng)一的diff補(bǔ)丁。該方法會返回一個應(yīng)用了補(bǔ)丁的新版本字符串。這里的補(bǔ)?。╬atch)可能是字符串形式的diff或者parsePatchstructuredPatch方法返回的輸出??蛇x的配置項(xiàng)有如下:

    • fuzzFactor: 拒絕應(yīng)用補(bǔ)丁之前允許比較的內(nèi)容的行數(shù)。默認(rèn)是0
    • compareLine(lineNumber, line, operation, patchContent) 用來比較給定的行內(nèi)容在應(yīng)用補(bǔ)丁時是否應(yīng)該被認(rèn)定為相等。默認(rèn)是使用嚴(yán)格相等來比較的,但是這容易與fuzzier比較相沖突。當(dāng)內(nèi)容應(yīng)該被拒絕時返回false。
  • JsDiff.applyPatches(patch, options) 應(yīng)用一個或者多個補(bǔ)丁。這個方法將會迭代補(bǔ)丁的內(nèi)容并且將其應(yīng)用在回調(diào)中傳入的內(nèi)容上。每個補(bǔ)丁被使用的整體工作流程是:

    • options.loadFile(index, callback) 調(diào)用者應(yīng)該加載文件的內(nèi)容并且將其傳遞給回調(diào)(callback(err, data))。傳入一個err將會中斷未來補(bǔ)丁的執(zhí)行
    • options.patched(index, content, callback) 該方法在每個補(bǔ)丁被使用時調(diào)用。傳入一個err將會中斷未來補(bǔ)丁的執(zhí)行
  • JsDiff.parsePatch(diffStr) 將一個補(bǔ)丁解析為結(jié)構(gòu)化數(shù)據(jù)。返回一個由補(bǔ)丁解析而來的JSON對象,該方法適合同applyPatch配合使用。該方法返回的內(nèi)容同JsDiff.structuredPatch返回的內(nèi)容結(jié)構(gòu)上一致。

  • convertChangesToXML(changes) 轉(zhuǎn)換一個changes的列表到序列化的XML格式

以上的所有可以接受一個可選的回調(diào)的方法,在該參數(shù)(callback)被省略時該方法工作在同步模式,當(dāng)這個參數(shù)被傳入時工作在異步模式。這使得能夠處理更大的范圍diff而不會使得事件流被長期掛起。callback要么作為最后一個參數(shù)被直接傳入要么作為options中的一個屬性被傳入。

Change Objects

上面的許多方法都會返回change對象(前文翻譯成描述改變的對象),這些對象通常包含以下的屬性:

  • value: 文本內(nèi)容
  • added: 如果是文本被插入新內(nèi)容的話,該值為true
  • removed: 如果是文本被移除內(nèi)容的話,該值為true

使用小結(jié)

上述的內(nèi)容主要是基于官方的文檔。這里結(jié)合筆者的實(shí)戰(zhàn)經(jīng)驗(yàn)來說說使用的細(xì)節(jié)。JsDiff的方法絕大多數(shù)的入?yún)⒍际亲址ǔ?code>JsDiff.diffJson,JsDiff.diffArrays等少數(shù)幾個api)。用于比較字符,單詞,句子或者文本文件時,需要將以上內(nèi)容都轉(zhuǎn)換成字符串,句子或者文本文件默認(rèn)使用\n作為分隔符。輸出通常是描述變化的對象組成的Array,方便二次開發(fā),如果只是想簡單輸出文件之間的diff,可以直接使用JsDiff.createTwoFilesPatch支持輸出格式化的內(nèi)容,不用額外處理。關(guān)于二次開發(fā)輸出滿足需求的樣式,這里給一個簡單的例子:

import React from 'react';
const jsDiff = require('diff');
import s from './index.css';
import cx from 'classnames';

const str1 = 'guanlanluditie';
const str2 = 'smartguanlanluditie';
const diffArr = jsDiff.diffChars(str1, str2);

const charColorMap = {
    'add': s.charAdd,
    'removed': s.charRemoved,
}

export default class Text extends React.Component {
    render() {
        return <div className={s.result}>
            比較結(jié)果: 
            {diffArr.map((item, index) => {
                const { value, added, removed } = item;
                const type = added ? 'add' : (removed ? 'removed' : '')
                return <span key={index} className={cx(charColorMap[type], s.charPreWrap)}>{value}</span>
                })
            }
        </div>
    }
}

關(guān)于使用diff庫實(shí)現(xiàn)類似于github的文件diff效果,可以參考筆者的一個倉庫,也就是上文中的演示代碼,倉庫地址,具體的實(shí)現(xiàn)思路后續(xù)會出一篇文詳述,稍候。

參考資料與相關(guān)鏈接

diff庫官方文檔
演示站點(diǎn)
演示站點(diǎn)代碼倉庫

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容