親バカエンジニアのナレッジ帳

webのエンジニアをやっており、日頃の開発で詰まったことや書き残しておきたいことを載せています。

文章どうしの差分を取得するならdiff-match-patchが便利

文章どうしの差分を取得

文章の差分を取得するような機能を作りたい時、diff-match-patchを使えば簡単に実装することができます。
PythonやGo、PHPなど、各種言語にライブラリが用意されていますが、今回はJavascriptのライブラリを使用し、フロントエンドだけで実装してみます。

実装方法は以下の通りです。
フレームワークはNuxt.js + TypeScriptで実装しました。

完成したツールのサンプルは以下になります。
jidou.jp

モジュールのインストール

まずはdiff-match-patchというモジュールをインストールしましょう。

TypeScriptを使用している型は型定義されたものをインストールします。
(ちゃんと用意されているみたい)

# npm
npm install --save @types/diff-match-patch
# yarn
yarn add @types/diff-match-patch

特に型定義が不要であれば以下のようにインストールしましょう。

# npm
npm install --save diff-match-patch
# yarn
yarn add diff-match-patch

コードの実装

あとはこんな感じでimportしてdiff_mainを実行すれば差分が取得できます。
結果は配列で取得できるのですが、配列の0の要素の値で取得結果を振り分けるといいでしょう。
配列の0の要素の値が-1は消失した文字群、0は差分なし、1は新しく付け足された文字群となります。

import DiffMatchPatch from 'diff-match-patch'

const _DiffMatchPatch: any = DiffMatchPatch
const dmp = new _DiffMatchPatch()
const allDiffs = dmp.diff_main(this.beforeText, this.afterText)
// 取得した結果は、最後にv-html="diffs"などで表示させると差分がわかりやすいです。
this.diffs = ''
allDiffs.forEach((diff: any) => {
  if (diff[0] === -1) {
    // サンプルです。消失した文字群は打ち消し線付きで赤背景色
    this.diffs += `<del style='background: #ecb4b4'>${diff[1]}</del>`
  }
  if (diff[0] === 0) {
    this.diffs += diff[1]
  }
  if (diff[0] === 1) {
    // サンプルです。新しく付け足された文字群は青背景色
    this.diffs += `<span style='background: #A0D7E2'>${diff[1]}</span>`
  }
})

上記は簡単な例ですが、以下ページのようにDiffの取り方は様々です。
https://www.npmjs.com/package/diff-match-patch
仕様に合わせて設定してみてください。

以上で終わりです。
こんな簡単に実装できてしまうんですね。