テキスト比較の仕組み
diff が答えるのは 1 つの問いです。最初のテキストを 2 つ目のテキストにするには、何を変えればよいか。このガイドでは、diff ツールがその答えを見つける方法、出力の読み方、そしてノイズではなく大事な変更が見えるように 2 つの版を準備する方法を説明します。
diff が示すもの
LeedyBox のテキスト比較を含め、ほとんどの diff ツールはテキストを行単位で比べます。結果の各行は 3 種類のどれかです。両方の版にある変更なしの行、元の版にだけある削除された行、新しい版にだけある追加された行です。「変更された行」という種類は別にないため、1 語だけ直した行は、削除された行と追加された行として 2 回現れます。
Dear customer,
- Your order ships on Monday.
+ Your order ships on Tuesday.
Kind regards
記号は昔からの慣例に従います。削除は -、追加は +、変更なしの行は空白です。多くの場合、赤と緑の色で同じ情報をもう一度示します。
行を対応づける仕組み
diff ツールは、両方のテキストに同じ順番で現れる最も長い行の並び、つまり最長共通部分列を探します。それらの行は変更なしとして残り、残りはすべて削除か追加になります。元が A、B、C、D で新しいテキストが A、C、B、D なら、最長の共通の並びはたとえば A、B、D の 3 行なので、C はある場所で削除され、別の場所で追加される形で移動が示されます。
同じ長さの答えが複数あることも多く、ツールによって選び方が違います。そのため、同じ 2 つのファイルでもプログラムによって diff が少し異なることがあります。Git は既定で Myers アルゴリズムを使い、代わりに patience と histogram も選べます。これらは閉じかっこだけの行が多いコードで、より読みやすい結果になることがよくあります。
最長の共通の並びを探す作業量は、片方のテキストの行数ともう片方の行数の積に応じて増えます。LeedyBox のツールは、まず先頭と末尾の同じ行を取り除いてから残りを比べ、その積が 4,000,000 を超えると、たとえば異なる行が約 2,000 行対 2,000 行あると、メッセージを表示して止まります。
Git やコードレビューの unified diff を読む
バージョン管理システムは、ファイルの変更部分だけを unified diff 形式で表示します。
--- a/config.yml
+++ b/config.yml
@@ -12,4 +12,5 @@
server:
- port: 8080
+ port: 8081
+ timeout: 30
database:
--- と +++ の行は古いファイルと新しいファイルの名前です。ハンクヘッダー @@ -12,4 +12,5 @@ は、このブロックが古いファイルでは 12 行目から 4 行、新しいファイルでは 12 行目から 5 行にわたるという意味です。変更の前後にある変更なしの行(既定で 3 行)が文脈を示します。LeedyBox のように全文を表示するツールはすべての行が見えるのでハンクヘッダーがなく、そのため出力をパッチとして適用することはできません。
役立つ比較のためにテキストを準備する
diff は意味ではなく文字を比べます。目に見えない小さな違いで行が異なるとされ、本当の変更が埋もれてしまうことがあります。
- スペースとタブ:行末のスペースや、一方がタブでもう一方がスペースの場合です。行末のスペースを消し、両方のインデントをそろえましょう。
- 見えない文字:Web ページやワープロからコピーしたテキストによくある、改行しないスペースやゼロ幅スペースです。
- Unicode の形:é のようなアクセント付きの文字は、1 文字として保存される場合と、e と結合用アクセントとして保存される場合があります。macOS のファイル名や一部の PDF のテキストは後者の形をよく使います。
- スマートクォートとダッシュ:ワープロは " を “ ” に、- を – に置き換えるため、貼り付けた写しが元の平らなテキストと一致しなくなります。
- 改行コード:Windows は行を CR LF で、macOS と Linux は LF で終えます。ブラウザーはテキストボックス内の改行をすべて LF にするので LeedyBox のツールではこの違いは見えませんが、ファイルを直接比べるツールでは見えます。
- データやコードの書式:インデントし直した JSON や順番の変わったキーは、ほぼすべての行を異なるものにします。先にキーを並べ替えてインデントをそろえるなど、両方の書式を同じにしましょう。
文章を比べる
一般的な文書では段落全体が 1 つの長い行であることが多く、1 語直しただけで段落全体が削除・追加として表示されます。2 つの習慣が役立ちます。比べる前に文ごとに改行して、変わった文だけが目立つようにする。または git diff --word-diff やワープロに組み込まれた変更履歴の比較機能のように、行の中の単語を比べるツールを使う。
PDF からコピーしたテキストには別の落とし穴があります。ページのレイアウトで折り返された位置で行が分かれ、行末で単語がハイフンで分割されていることがあります。元の文書と比べる前に、各段落の行をつなぎ直してください。
行単位の diff ではわからないこと
- 移動:別の場所に移した段落は、ある場所で削除され、別の場所に追加されたものとして現れます。
--color-movedを付けた git のように、移動したブロックを別に示すツールもあります。 - 意味:同じことを別の言葉で書いた 2 つのテキストは完全に違って見え、"not" が 1 つ抜けたような 1 文字の変更は、小さく見えても文の意味を逆にすることがあります。
- バイナリの内容:Word 文書、PDF、画像はプレーンテキストではありません。先にテキストを取り出すか、そのファイルを作ったプログラムの比較機能を使ってください。
文書を比べるときのプライバシー
契約書、設定ファイル、ログには、名前、鍵、パスワードが含まれていることがよくあります。オンラインの比較サービスの中には、貼り付けたテキストをサーバーに保存し、共有リンクで公開するものもあります。LeedyBox のテキスト比較はブラウザー内で動き、テキストを送信も保存もしませんが、それでも設定ファイルをどこかに貼り付ける前には秘密の情報を消しておくのが賢明です。
よくある質問
1 語しか直していないのに段落全体が変更扱いになるのはなぜですか?
段落が 1 行で、行単位の diff は行全体を比べるからです。比べる前にテキストを文や短い行に分けるか、単語単位の比較を使ってください。
スペースの違いを無視できますか?
LeedyBox のツールは行を厳密に比べます。行末のスペースを消し、タブをスペースに変えるなどして、先に両方のテキストを整えてください。ファイルを比べる場合、git には --ignore-space-change などのオプションがあります。
Word 文書を 2 つ比べるにはどうすればよいですか?
Word には書式の変更も示す比較機能が組み込まれています。文言だけを比べたいなら、両方の文書のテキストをコピーしてテキスト比較ツールに入れてください。
3 方向マージ(three-way merge)とは何ですか?
2 人が同じ元の文書を編集したとき、マージツールはそれぞれの版を共通の元と比べます。別々の場所の変更は自動で統合され、同じ行への変更は人が解決すべき競合として示されます。