- 技術 💻
テキスト比較(差分チェック)|2つの文章の違いを色分け・diffの読み方
結論
テキスト比較(差分チェック)は、2つの文章を行ごとに比べ、変わった行と、その行の中で変わった文字を色分けして示す作業です。下のツールに変更前・変更後の文章を貼るだけで比べられます。見た目が同じなのに「違う」と出るときは、改行コード・BOM・全角空白・ゼロ幅スペース・濁点の分かれた文字など、目に見えない文字の違いを疑います。
この記事でわかること
- ツールの使い方と、結果(色・集計・diff 形式)の読み方
- diff・git diff・Python difflib の出力の読み方と、同じ文章で比べた実行結果
- 「同じなのに違う」と出る10の原因を手元で再現した結果と、消し方の表
テキスト比較を読み込み中です。
ツールの使い方:左の「変更前(元の文章)」と右の「変更後(新しい文章)」に文章を貼ると、入力が止まって少しすると自動で比べ直します。変わった行は、変更前が赤、変更後が緑の帯になり、行の中で違う文字だけが濃い色になります。上には「変更N行・追加N行・削除N行」の集計が出ます。
- 無視の切り替え:「空白の違いを無視」「大文字・小文字を無視」「全角・半角の英数字を同じとみなす」を選べます。
- 表示:「横に並べる」と「1列で見る」を切り替えられます。「左右を入れ替え」で変更前と変更後を入れ替えます。
- コピー:「差分をコピー(diff 形式)」で、行頭に
-(削除)・+(追加)・空白2つ(同じ)を付けた形をコピーできます。 - 大きさと送信:5,000行まで比べられます。貼った文章はこの端末の中だけで比べ、どこにも送信しません。
この記事で実際に動かしたもの:上のツールを Chromium で開いて同じ文章を貼った結果、GNU diff・git diff・Python difflib・patch の出力、目に見えない違い10種類を入れたファイルの比較結果、5,000行の比較にかかった時間を記録しました。
flowchart TD
A[2つの文章を行に分ける] --> B[無視の設定で<br>行をそろえる]
B --> C[行どうしを比べて<br>同じ・削除・追加を決める]
C --> D[削除と追加が続く所で<br>似た行を組にする]
D --> E[組にした行は<br>文字ごとに比べて色を付ける]
やりたいことごとに、いちばん早い方法を先にまとめます。
| やりたいこと | いちばん早い方法 | 詳しい節 |
|---|---|---|
| 2つの文章の違いを色分けで見たい | このページのツールに貼る | ツールの使い方 |
| diff の結果(- と +、@@)を読みたい | - は変更前だけ、+ は変更後だけ、@@ は行番号 | diff の読み方 |
| 同じに見えるのに差分が出る | 改行コード・BOM・全角空白を疑い、cat -A で見る | 同じなのに違うと出る原因 |
| 改行コードの違いを無視したい | diff --strip-trailing-cr、git diff --ignore-cr-at-eol | 同じなのに違うと出る原因 |
| 日本語の文の中の違いを git diff で見たい | git diff --word-diff-regex=. | git diff で文章を比べる |
| Windows でファイルを比べたい | fc コマンド、VS Code の比較 | Windows・Mac・VS Code・Word |
| Word の文書を比べたい | [校閲]タブの[比較] | Windows・Mac・VS Code・Word |
| パッチとして渡したい | diff -u の出力を使う(ツールのコピーはパッチにならない) | よくあるつまずき |
| 差分の仕組みを知りたい | LCS(共通部分)を最大にし、残りを削除・追加とみなす | 差分のアルゴリズム |
確認環境:Ubuntu 24.04.5 LTS(Linux カーネル 6.18、x64、2 CPU)の上で、GNU diffutils 3.10(diff・cmp・sdiff)、GNU patch 2.7.6、Git 2.43.0、Python 3.13.18 の difflib、Node.js 22.23.4 から動かした Chromium 153(Playwright、ヘッドレス)を使いました。ツールは、このサイトのテーマの JavaScript と CSS を読み込んだ確認用のページを 127.0.0.1 相当のアドレスで開き、文章を貼って結果の表示・集計・コピーした内容を読み取りました。見本のファイル(会議の案内文・設定ファイル・C のソース)は自作で、外部のサービスには何も送っていません。Git の設定は作業用のフォルダーを HOME にして作り、ホームと共有の場所には何も置いていません。Windows の fc、Word の比較、VS Code の比較は手元で動かせないため、Microsoft Learn・Microsoft サポート・Visual Studio Code の公式ドキュメントで確かめた範囲だけを書いています。図は mermaid で描画を確かめています(確認日 2026年11月7日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「テキスト比較(差分チェック)|2つの文章の違いを色分け・diffの読み方」
テキスト比較ツールの使い方(2つの文章の差分チェック)
この節では、ツールで文章を比べる手順と、どんな場面で使うと便利かが分かります。
テキスト比較は「どこが変わったか」を人の目で探す手間を、機械に任せる作業です。契約書や案内文の新旧、設定ファイルのバックアップと今の版、翻訳の前後、コードの修正前後など、2つの版がある文章ならどれにも使えます。
変更前を左、変更後を右に貼る
左右を逆に貼ると、追加と削除が入れ替わって見えます。逆に貼ったときは「左右を入れ替え」を押します。
集計を見る
「違いはありません(N行が同じです)」なら完全に同じです。違いがあれば「変更N行・追加N行・削除N行」が出ます。
色の付いた行を上から読む
赤が変更前だけにある行、緑が変更後だけにある行です。左右に並んだ赤と緑は「変更」で、濃い色の文字が実際に変わった所です。
気にしない違いを無視する
空白の数・大文字と小文字・全角と半角の英数字の違いが本題でなければ、チェックを入れて比べ直します。
差分をコピーして共有する
「差分をコピー(diff 形式)」で、チャットやレビューのコメントに貼れる形になります。
ツールに最初から入っている見本(会議の案内文)で確かめると、集計は次のように出ました。
| 変更前(左) | 変更後(右) | ツールの判定 | 濃い色の文字 |
|---|---|---|---|
| 1 会議は10時から開始します。 | 1 会議は10時30分から開始します。 | 変更 | 30分 |
| 2 場所は第1会議室です。 | 2 場所は第1会議室です。 | 同じ | なし |
| 3 資料は前日までに共有します。 | (空き) | 削除 | 行全体 |
| 4 参加者:田中、佐藤 | 3 参加者:田中、佐藤、鈴木 | 変更 | 、鈴木 |
| (空き) | 4 終了は12時の予定です。 | 追加 | 行全体 |
集計は「変更 2行・追加 1行・削除 1行」でした。3行目の「資料は…」と、右の3行目の「参加者:…」は位置が同じですが、内容が似ていないため組にせず、左の4行目と右の3行目を「変更」として並べています。
差分チェックの結果の読み方(色・集計・変更と追加・削除)
この節では、ツールの「変更」「追加」「削除」がどう決まるかと、1列表示・コピーの形が分かります。
1変更
削除と追加が続く所で、内容が似ている行どうしを組にしたもの。組にした行は文字ごとに比べ、違う文字だけを濃くする。
2追加
変更後だけにある行。似た行が変更前に無いので、組にならなかった行。
3削除
変更前だけにある行。短い行で中身がほとんど違うと、位置が同じでも削除と追加に分かれる。
「1列で見る」に切り替えると、同じ見本は次の順に並びました。行頭の記号は、diff の unified 形式(後の節)と同じ考え方です。
1 - 会議は10時から開始します。
1 + 会議は10時30分から開始します。
2 場所は第1会議室です。
3 - 資料は前日までに共有します。
4 - 参加者:田中、佐藤
3 + 参加者:田中、佐藤、鈴木
4 + 終了は12時の予定です。
「差分をコピー(diff 形式)」でコピーされた文字列は、次のとおりでした。
--- 変更前
+++ 変更後
- 会議は10時から開始します。
+ 会議は10時30分から開始します。
場所は第1会議室です。
- 資料は前日までに共有します。
- 参加者:田中、佐藤
+ 参加者:田中、佐藤、鈴木
+ 終了は12時の予定です。
- 行番号は、左が変更前、右が変更後の行番号です。 削除や追加があると、左右の番号がずれていきます。
- 短い行の大文字・小文字だけを変えた例(
name: rjc→NAME: RJC)では、似ていないと判定され「追加 1行・削除 1行」になりました。「大文字・小文字を無視」を入れると「違いはありません」になります。
diff の読み方(normal・-u・-c・-y の記号の意味)
この節では、同じ2つのファイルを diff の4つの形式で出した実物と、記号の読み方が分かります。
diff の出力は形式が違っても、伝えていることは「どの行を消し、どの行を足せば、左が右になるか」です。ツールの見本と同じ文章を before.txt・after.txt に保存して比べました。
normal 形式(オプションなし)
$ diff before.txt after.txt
1c1
< 会議は10時から開始します。
---
> 会議は10時30分から開始します。
3,4c3,4
< 資料は前日までに共有します。
< 参加者:田中、佐藤
---
> 参加者:田中、佐藤、鈴木
> 終了は12時の予定です。
$ echo $?
1
1c1 は「左の1行目を、右の1行目に変える(change)」、3,4c3,4 は「左の3〜4行目を右の3〜4行目に変える」です。足すだけなら a(add)、消すだけなら d(delete)になります。< が左(変更前)、> が右(変更後)の行です。
unified 形式(-u。いちばんよく見る形)
$ diff -u before.txt after.txt
--- before.txt
+++ after.txt
@@ -1,4 +1,4 @@
-会議は10時から開始します。
+会議は10時30分から開始します。
場所は第1会議室です。
-資料は前日までに共有します。
-参加者:田中、佐藤
+参加者:田中、佐藤、鈴木
+終了は12時の予定です。
(見出しの行の後ろに付く更新日時は省いています。)@@ -1,4 +1,4 @@ は「左の1行目から4行分と、右の1行目から4行分を示す」という意味で、この固まりを「ハンク(hunk)」と呼びます。行頭が - は左だけ、+ は右だけ、空白1つは両方にある行です。git diff・GitHub のプルリクエスト・パッチファイルは、この形です。
context 形式(-c)と横並び(-y)
$ diff -c before.txt after.txt
*** before.txt
--- after.txt
***************
*** 1,4 ****
! 会議は10時から開始します。
場所は第1会議室です。
! 資料は前日までに共有します。
! 参加者:田中、佐藤
--- 1,4 ----
! 会議は10時30分から開始します。
場所は第1会議室です。
! 参加者:田中、佐藤、鈴木
! 終了は12時の予定です。
$ diff -y -W 80 before.txt after.txt
会議は10時から開始します。 | 会議は10時30分から開始します。
場所は第1会議室です。 場所は第1会議室です。
資料は前日までに共有します。 | 参加者:田中、佐藤、鈴木
参加者:田中、佐藤 | 終了は12時の予定です。
(-y の出力はタブで桁をそろえるため、記事では空白に置き換えています。)! は変わった行、| は左右で違う行です。diff は削除と追加が続く所を位置の順に並べるだけで、似た行どうしを探して組にはしません。そのため -y では「資料は…」と「参加者:…」が同じ行に並びました。ツールで「参加者」どうしが並んだのは、似た行を組にする処理を足しているためです。
| 記号・表記 | 意味 | 出る形式 |
|---|---|---|
< / > | 左(変更前)の行 / 右(変更後)の行 | normal |
1c1・3a4・5d4 | 変える・足す・消す(左の行番号 記号 右の行番号) | normal |
- / + / 空白 | 左だけ / 右だけ / 両方にある | unified(-u) |
@@ -1,4 +1,4 @@ | ハンクの範囲(開始行,行数) | unified(-u) |
! | 変わった行 | context(-c) |
| / < / > | 左右で違う / 左だけ / 右だけ | 横並び(-y) |
\ No newline at end of file | ファイルの最後に改行が無い | すべて |
終了コードは、同じなら0、違いがあれば1、ファイルが無いなどの問題があれば2です(GNU diffutils のマニュアルの記述と、手元の echo $? の結果が一致しました)。シェルスクリプトで「違いがあるか」だけ知りたいときは diff -q を使い、出力は Files before.txt and after.txt differ の1行でした。オプションの一覧と patch での適用は、関連記事「diffコマンドの使い方|-uの読み方・patch適用・オプション一覧」で扱っています。
「同じなのに違う」と出る原因(改行コード・BOM・全角空白)
この節では、見た目が同じなのに差分が出る10の原因を、diff とツールで実際に比べた結果が分かります。
差分ツールは文字を「見た目」ではなく「文字の番号(バイト)」で比べます。そのため、画面では同じに見える文字でも、番号が違えば違う行として出ます。name: rjc と port: 8080 の2行のファイルを基準にし、1か所ずつ見えない違いを入れたファイルを作って比べました。
| 原因 | diff の結果 | diff で消すオプション | ツールで消える設定 |
|---|---|---|---|
| 改行コード CRLF と LF | 全行が違う(1,2c1,2) | --strip-trailing-cr・-w | 設定なしで同じと判定 |
| 先頭の BOM(EF BB BF) | 1行目だけ違う | なし(BOM を消してから比べる) | 空白の違いを無視 |
| 行末の空白 | その行が違う | -b・-w | 空白の違いを無視 |
| 全角空白(U+3000)と半角空白 | その行が違う | なし(-w でも消えない) | 空白の違いを無視・全角半角 |
| ノーブレークスペース(U+00A0) | その行が違う | なし | 消えない |
| ゼロ幅スペース(U+200B) | その行が違う | なし | 消えない |
| 大文字と小文字 | その行が違う | -i | 大文字・小文字を無視 |
| 全角英数(name・8080) | その行が違う | なし | 全角・半角を同じとみなす |
| 濁点が分かれた文字(NFD) | その行が違う | なし(NFC に直してから比べる) | 消えない |
| 最後の行の改行の有無 | \ No newline at end of file | なし | 空の行1行の追加として出る |
ツールの欄は、5通りの設定(なし・空白だけ・大文字小文字だけ・全角半角だけ・3つすべて)で比べた結果です。目立った結果を3つ挙げます。
CRLF は最初から同じ扱い
ツールは行に分けるときに CRLF・CR・LF をそろえるため、改行コードだけの違いは「違いはありません」になった。
diff は全行が違う
BOM は空白の無視で消えた
「空白の違いを無視」は行の前後の空白を落とす。BOM も行頭の空白として落ち、同じと判定された。
diff には消すオプションが無い
消えない3つ
NBSP・ゼロ幅スペース・濁点の分かれた文字は、どの設定でも違いとして残った。次の節の方法で文字を見つける。
本当に違う文字として扱う
diff での実際の出力は、次のように「見た目が同じ2行」が並びます。
$ diff lf.txt crlf.txt
1,2c1,2
< name: rjc
< port: 8080
---
> name: rjc
> port: 8080
$ diff --strip-trailing-cr lf.txt crlf.txt; echo $?
0
$ diff -w lf.txt zspace.txt
1c1
< name: rjc
---
> name: rjc
$ diff lf.txt noeol.txt
2c2
< port: 8080
---
> port: 8080
\ No newline at end of file
GNU diff の -w は、ロケールを C・C.UTF-8 のどちらにしても全角空白を空白として扱いませんでした。改行コードの違いは Git で起きることが多く、設定で防ぐ方法は関連記事「Git改行コード設定|autocrlfと.gitattributesの違い」で扱っています。
見た目が似ていて文字が違う例もあります。電話番号の 03-1234-5678 のハイフン(U+002D)を、マイナス記号(U+2212)にした行は、diff で違う行として出ました。全角と半角、ハイフンとマイナスの変換は、関連記事「全角⇔半角変換の早見表|Java・JS・Python・Excel・SQL」で扱っています。
見えない違いを見つける方法(cat -A・od・Python)
この節では、差分の出た行の中から、目に見えない文字を見つけて名前を確かめる方法が分かります。
見えない文字は、記号や16進数に置き換えて表示すると見つかります。Linux のターミナルなら cat -A、文字の番号まで見るなら od、名前まで知りたいなら Python の unicodedata が使えます。
$ for f in crlf bom trail zspace zwsp nbsp; do printf '%-7s ' $f; head -1 $f.txt | cat -A; done
crlf name: rjc^M$
bom M-oM-;M-?name: rjc$
trail name: rjc $
zspace name:M-cM-^@M-^@rjc$
zwsp name: rM-bM-^@M-^Kjc$
nbsp name:M-BM- rjc$
$ file lf.txt crlf.txt bom.txt
lf.txt: ASCII text
crlf.txt: ASCII text, with CRLF line terminators
bom.txt: Unicode text, UTF-8 (with BOM) text
^M が CR、$ が行の終わり、M- で始まる並びが ASCII 以外の文字のバイトです。行末の空白は $ の直前の空白で分かります。濁点の分かれた文字は cat -A では分かりにくいため、バイトで見ると、「デ」が e3 83 86(テ)と e3 82 99(濁点だけの文字)の2つに分かれていました。ファイルの大きさも、NFC が32バイト、NFD が35バイトと3バイト違いました。
文字の名前まで出す小さなスクリプトを書き、すべてのファイルに当てました。
import sys, unicodedata
for path in sys.argv[1:]:
data = open(path, 'rb').read()
if data.startswith(b'\xef\xbb\xbf'): print(path, '先頭に BOM (EF BB BF)')
if b'\r\n' in data: print(path, '改行が CRLF', data.count(b'\r\n'), '個')
if not data.endswith(b'\n'): print(path, '最後に改行なし')
text = data.decode('utf-8-sig')
for no, line in enumerate(text.split('\n'), 1):
for col, ch in enumerate(line, 1):
cat = unicodedata.category(ch)
if ch in ' −' or cat in ('Mn', 'Cf', 'Zs') and ch != ' ':
print(f'{path}:{no}:{col} U+{ord(ch):04X} {unicodedata.name(ch, "?")}')
if line != unicodedata.normalize('NFC', line):
print(f'{path}:{no} NFC でない(濁点などが分かれている)')
if line.rstrip('\r') != line.rstrip('\r').rstrip(' \t'):
print(f'{path}:{no} 行末に空白')
crlf.txt 改行が CRLF 2 個
bom.txt 先頭に BOM (EF BB BF)
trail.txt:1 行末に空白
zspace.txt:1:6 U+3000 IDEOGRAPHIC SPACE
noeol.txt 最後に改行なし
zwsp.txt:1:8 U+200B ZERO WIDTH SPACE
nbsp.txt:1:6 U+00A0 NO-BREAK SPACE
nfd.txt:1:8 U+3099 COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK
nfd.txt:1 NFC でない(濁点などが分かれている)
hy2.txt:1:8 U+2212 MINUS SIGN
hy2.txt:1:13 U+2212 MINUS SIGN
見つけた後の直し方は、次のとおりです。手元でいずれも、直した後に diff の終了コードが0になりました。
- BOM:
sed '1s/^\xEF\xBB\xBF//' bom.txtで先頭の3バイトを消してから比べる。 - 濁点の分かれた文字:Python の
unicodedata.normalize('NFC', 文字列)で NFC にそろえる。Mac で作ったファイル名やコピーした文字で起きやすい違いです。 - 全角英数と全角空白:
unicodedata.normalize('NFKC', 'name ABC123')はname ABC123になりました。ただし NFKC は「①」→「1」のように他の文字も変えるため、比べる前の一時的なそろえ方として使います。
濁点の分離のように文字化けと間違えやすい原因は、関連記事「文字化けの原因8選|濁点分離・utf8mb4・絵文字の文字数」で扱っています。
git diff で文章を比べる(--word-diff と日本語の注意)
この節では、Git の管理外のファイルを git diff で比べる方法と、日本語の文で単語単位の差分を出すときの注意が分かります。
git diff --no-index ファイル1 ファイル2 で、Git のリポジトリの外にある2つのファイルも比べられます。出力は diff -u とほぼ同じで、終了コードも違いがあれば1でした。
行の中の違いを見る --word-diff は、空白で区切った並びを1語とみなします(Git の公式ドキュメント)。日本語の文には空白が無いため、行全体が1語になります。
$ git diff --no-index --word-diff before.txt after.txt
@@ -1,4 +1,4 @@
[-会議は10時から開始します。-]{+会議は10時30分から開始します。+}
場所は第1会議室です。
[-資料は前日までに共有します。-]
[-参加者:田中、佐藤-]{+参加者:田中、佐藤、鈴木+}
{+終了は12時の予定です。+}
$ git diff --no-index --word-diff-regex=. before.txt after.txt
@@ -1,4 +1,4 @@
会議は10時{+30分+}から開始します。
場所は第1会議室です。
[-資料は前日までに共有します。-]参加者:田中、佐藤{+、鈴木+}
{+終了は12時の予定です。+}
--word-diff-regex=. は「1文字を1語とみなす」指定で、公式ドキュメントにも文字単位の差分の例として載っています。日本語の文では、ツールで濃く示された「30分」「、鈴木」と同じ所が取り出せました。[-…-] が消えた部分、{+…+} が足された部分です。色だけで見たいときは --color-words=. を使います。
| オプション | 何を無視・表示するか | 手元の結果 |
|---|---|---|
--ignore-cr-at-eol | 行末の CR を無視 | CRLF と LF が同じ(終了コード0) |
-w | 空白をすべて無視 | 全角空白・NBSP は違いのまま(終了コード1) |
-b | 空白の量の違いを無視 | 行末の空白が消える |
--stat | 増えた行・減った行の数だけ | 3 insertions(+), 3 deletions(-) |
--check | 行末の空白などを警告 | t.txt:1: trailing whitespace. |
ブランチどうし・コミットどうしの比べ方は、関連記事「git diffの使い方|早見表・オプション一覧・ブランチ間・ファイル名だけ」で扱っています。
Windows・Mac・VS Code・Word でテキスト比較する方法
この節では、OS やアプリごとの比べ方を、公式ドキュメントで確かめた範囲で分かります。
どの OS でも使えるのは、このページのツールと VS Code です。ファイルのまま比べたいならコマンド、Word の文書なら Word の比較機能が向きます。
Windows:fc コマンド
Microsoft Learn によると、Windows の fc は2つのファイルを比べて違いを表示するコマンドで、主なオプションは次のとおりです。
| オプション | 意味(Microsoft Learn の記述の要約) |
|---|---|
/c | 大文字と小文字を無視する |
/w | 連続した空白・タブを1つとみなし、行の先頭と末尾の空白を無視する |
/n | 行番号を表示する |
/u | Unicode テキストとして比べる |
/b | バイト単位で比べる(.exe などの既定) |
/lb<n> | 行バッファの行数(既定は100行) |
終了コードは、同じなら0、違えば1、エラーなら2です。PowerShell では fc が Format-Custom の別名になっているため、fc.exe と書く必要があると明記されています。また、連続して100行を超えて違う所があると、Resynch failed. Files are too different. と表示して比較をやめることがあります。
VS Code:エクスプローラーとコマンドライン(Windows・Mac・Linux)
VS Code の公式ドキュメントによると、エクスプローラーで2つのファイルを選び、右クリックのメニューから Compare Selected を選ぶと差分を表示できます。コマンドラインでは code -d ファイル1 ファイル2(--diff)で差分の画面を開けます。3者マージには code -m があります。
Word:[校閲]タブの[比較]
Microsoft サポートの手順では、[校閲]タブの[比較]から、「元の文書」と「変更された文書」を選んで[OK]を押します。結果は新しい3つ目の文書として開き、変更が変更履歴の形で示され、元の文書は変わりません。比べる項目(コメント・書式・テキストなど)と、変更を文字単位・単語単位のどちらで示すかを選べます。Word 2019 for Mac のヘルプにも、[校閲]タブの[比較]から元の文書と変更された文書を選ぶ手順が載っています。
Excel:EXACT 関数
セルどうしが同じかだけを知りたいときは、Excel の =EXACT(A1,B1) が使えます。Microsoft サポートによると、大文字と小文字は区別し、書式の違いは無視して、同じなら TRUE を返します。どこが違うかは示さないため、違う行を見つけた後はツールに貼って確かめます。
手早く1回比べる
このページのツール(貼るだけ・送信しない)
Excel の EXACT(同じかどうかだけ)
Word の[比較](Word の文書どうし)
ファイルのまま・くり返し比べる
diff・git diff(Linux・Mac・Git Bash)
fc.exe(Windows)
VS Code の Compare Selected・code -d
差分のアルゴリズム(LCS と Myers の考え方)
この節では、差分ツールが「どこが変わったか」をどう決めているかを、小さな例と実測で分かります。
差分は「両方に同じ順番で出てくる要素の並び(最長共通部分列、LCS)」をできるだけ長く取り、残りを削除と追加とみなして作ります。LCS が長いほど、削除と追加の数(編集の回数)は少なくなります。
- 1比べる単位を決める行・単語・文字。ツールはまず行、変わった行の中は文字で比べる
- 2共通部分(LCS)を探す両方に同じ順で出てくる並びのうち、最も長いもの
- 3残りを削除・追加にする左だけに残った要素が削除、右だけに残った要素が追加
- 4見やすく整える前後の同じ行を足してハンクにする、似た行を組にする
Python で、LCS を表(動的計画法)で求める方法と、Myers のアルゴリズム(1986年の論文で示された、編集の回数 D が小さいほど速く終わる方法)を書き、同じ入力で比べました。Myers のアルゴリズムは GNU diff や Git の既定(myers)の土台で、このページのツールも行と文字の比較に使っています。
ABCABBA → CBABAC: LCS=4(CBBA) 削除3+追加2=D5 / Myers D=5 調べた点=30 / 表の升=56
kitten → sitting: LCS=4(ittn) 削除2+追加3=D5 / Myers D=5 調べた点=22 / 表の升=56
2000行で10行変更: LCS表 4,004,001升 0.52秒 / Myers D=20 調べた点 2,211 0.3ミリ秒
表の方法は行数の掛け算に比例して重くなりますが、Myers は「違いが少ないほど速い」ため、ほとんど同じ2つの版を比べる差分チェックに向いています。逆に、全く違う2つの文章では D が大きくなり、時間がかかります(ツールで5,000行すべてを変えた例は、後の節で示します)。
- 最短の差分は1つとは限りません。 ABCABBA と CBABAC では、LCS が CBBA でも BABA でも長さは4です。どれを選ぶかで見た目が変わるため、同じ D でも読みやすい結果と読みにくい結果があります。
diff アルゴリズムで結果が変わる例(myers・histogram)
この節では、同じ2つのファイルでも、アルゴリズムによって差分の見え方が変わる例が分かります。
Git では --diff-algorithm で myers(既定)・minimal・patience・histogram を選べます。関数を1つ足し、1つ消し、1行を消した C のファイルで比べると、4つとも「10 insertions(+), 11 deletions(-)」で数は同じでした。しかし、見え方は大きく違いました。
$ git diff --no-index --diff-algorithm=myers a.c b.c (一部)
-// Frobs foo heartily
-int frobnitz(int foo)
+int fib(int n)
{
- int i;
- for(i = 0; i < 10; i++)
+ if(n > 2)
{
- printf("Your answer is: ");
- printf("%d\n", foo);
+ return fib(n-1) + fib(n-2);
}
+ return 1;
}
$ git diff --no-index --diff-algorithm=histogram a.c b.c (一部)
+int fib(int n)
+{
+ if(n > 2)
+ {
+ return fib(n-1) + fib(n-2);
+ }
+ return 1;
+}
+
// Frobs foo heartily
int frobnitz(int foo)
{
int i;
for(i = 0; i < 10; i++)
{
- printf("Your answer is: ");
printf("%d\n", foo);
myers は { や } のようなどこにでもある行を共通部分として使うため、2つの関数が混ざって見えます。histogram(patience も同じ出力でした)は、まれにしか出ない行を手がかりにするため「fib を足した」「printf を1行消した」「fact を消した」とまとまって見えます。GNU diff -u の出力は myers と同じ形でした。
同じファイルをこのページのツールに貼ると、集計は「変更 1行・追加 9行・削除 10行」で、fib の関数がまとまって追加、fact の関数がまとまって削除、frobnitz(fact(10)); と frobnitz(fib(10)); が変更(濃い色は act と ib)になりました。Git の出力をいつも histogram にしたいときは git config diff.algorithm histogram で設定できます。
言語・コマンド別の差分チェック(Python difflib・速さの実測)
この節では、プログラムの中で差分を取る方法と、5,000行を比べたときの速さが分かります。
Python には標準ライブラリの difflib があり、unified 形式の差分も、行の中の違いを示す形も作れます。
import difflib
a = open('before.txt', encoding='utf-8').read().splitlines()
b = open('after.txt', encoding='utf-8').read().splitlines()
for l in difflib.ndiff(a, b): print(l)
print(difflib.SequenceMatcher(None, a[0], b[0]).ratio())
- 会議は10時から開始します。
+ 会議は10時30分から開始します。
? +++
場所は第1会議室です。
- 資料は前日までに共有します。
- 参加者:田中、佐藤
+ 参加者:田中、佐藤、鈴木
? +++
+ 終了は12時の予定です。
0.9
? の行は、すぐ上の行のどの文字が変わったかを +(足した)・-(消した)・^(変えた)で指す行です。位置を文字数で数えるため、全角の文字があると印の位置が画面上でずれます。上の例でも「30分」の真下には来ていません。日本語の文では、ツールの色分けや --word-diff-regex=. のほうが読みやすい結果でした。SequenceMatcher(...).ratio() は2つの文字列の似ている度合い(0〜1)で、1行目どうしは0.90、「資料は…」と「参加者:…」は0.00でした。
同じ5,000行のファイル(1,000行を変更)で、道具ごとの時間を測りました。
| 道具 | かかった時間 | 結果 |
|---|---|---|
| GNU diff | 6〜7ミリ秒(3回) | 違う行 2,000行(< と >) |
| git diff --no-index --stat | 10ミリ秒 | 1000 insertions, 1000 deletions |
| Python difflib.unified_diff | 880ミリ秒 | + と - の行 2,002行(見出し2行を含む) |
| このページのツール(Chromium) | 819〜1,000ミリ秒(2回) | 変更 1000行・追加 0行・削除 0行 |
ツールは行の比較に加えて、変更した1,000行それぞれで文字ごとの比較と表示まで行うため、diff より時間がかかります。違いが少ないときは速く、5,000行で10行の変更なら59〜75ミリ秒、100行の変更なら70〜75ミリ秒でした。
よくあるつまずき(エラー・表示の原文つき)
この節では、テキスト比較でよく出る表示と、その原因・直し方が分かります。
| 症状・表示 | 原因 | 直し方 |
|---|---|---|
| 全行が違うと出る | 改行コードが CRLF と LF で違う | diff --strip-trailing-cr・git diff --ignore-cr-at-eol。ツールは同じ扱い |
| 1行目だけ違うと出る | 片方の先頭に BOM がある | BOM を消すか、ツールで「空白の違いを無視」 |
| 見た目が同じ行が違うと出る | 全角空白・NBSP・ゼロ幅スペース・NFD | cat -A・od・Python で文字を確かめる |
\ No newline at end of file | 最後の行に改行が無い | エディタで最後に改行を入れる設定にする |
patch: **** Only garbage was found in the patch input. | ツールのコピーした形を patch に渡した(@@ の行が無い) | パッチには diff -u の出力を使う |
diff: nofile: No such file or directory(終了コード2) | ファイル名の誤り | パスを確かめる |
Resynch failed. Files are too different. | fc で100行を超えて違う所が続いた | /lb で行数を増やす(Microsoft Learn)か、別の道具で比べる |
| 「違いが多すぎるため比べられませんでした。」 | ツールで全く違う長い文章を比べた | 比べる範囲を分ける。diff で比べる |
| 「5,000行までの文章を比べられます。」 | どちらかが5,001行以上 | 分けて貼るか、diff・git diff を使う |
ツールで「違いが多すぎる」と出たのは、5,000行をすべて別の文にしたときで、表示までに約2秒かかりました。ツールの「差分をコピー」は読むための形で、patch で適用できる形ではありません。diff -u before.txt after.txt > real.diff で作ったパッチは、patch pt.txt < real.diff で当てた後、cmp で after.txt と一致しました。
機密の文章を比べるとき
確かめる問い:「貼った文章がどこかに送られるか」
Git のマージで出る <<<<<<< の印は差分ではなく、2つの変更がぶつかった所の印です。読み方は関連記事「Gitのコンフリクトの解消方法|マーカーの読み方から防ぎ方まで」で扱っています。
どれで比べるかの判断表(ツール・diff・git diff・Word)
この節では、場面ごとにどの道具で比べるとよいかが分かります。
| 場面 | 向く道具 | 理由 |
|---|---|---|
| メール・案内文・原稿の新旧を1回見る | このページのツール | 貼るだけ。行の中の違う文字まで色が付く |
| 見た目は同じなのに違うか確かめる | ツール+cat -A・Python | 無視の設定で消えるか試し、残ったら文字を調べる |
| 設定ファイル・ログをサーバー上で比べる | diff -u | ファイルのまま。終了コードでスクリプトに組み込める |
| コードの変更を確かめる・共有する | git diff(histogram も試す) | 履歴と結び付く。パッチにできる |
| 日本語の文の中の違いをコマンドで見る | git diff --word-diff-regex=. | 空白の無い文でも文字単位で示せる |
| Word の契約書・報告書 | Word の[比較] | 書式・コメントも比べ、変更履歴の形で残せる |
| Windows でファイルを比べる | fc.exe・VS Code | 標準で入っている。VS Code は画面で比べられる |
| 5,001行以上・全く違う長い文章 | diff・git diff | ツールの上限を超える。diff は5,000行でも数ミリ秒 |
- 1左が変更前、右が変更後になっているか逆だと追加と削除が入れ替わる。「左右を入れ替え」で直せる
- 2無視の設定を入れたまま、本当の違いを見落としていないか空白・大小・全半角の違いが本題の文章(コード・ID)では、設定を外して比べ直す
- 3「同じなのに違う」行の文字を確かめたかNBSP・ゼロ幅スペース・NFD はどの設定でも消えない
- 4共有するのは読むための差分か、当てるためのパッチかパッチなら diff -u か git diff の出力を渡す
よくある質問
この節では、テキスト比較と diff についてよく聞かれる質問への答えが分かります。
Q. 貼った文章はどこかに送信されますか。
このページのツールは、ブラウザの中で比べ、どこにも送信しません。
Q. ファイルを読み込んで比べられますか。
このツールは貼り付けて比べる形です。ファイルのまま比べるなら diff -u・git diff --no-index・fc.exe・VS Code の Compare Selected が使えます。
Q. 単語単位で比べられますか。
ツールは行で比べ、変わった行の中を文字で示します。コマンドでは git diff --word-diff が空白区切りの単語単位、--word-diff-regex=. が文字単位です。日本語の文は空白が無いため、文字単位のほうが違いが分かりやすくなります。
Q. 改行コードだけが違うファイルはどう出ますか。
diff では全行が違うと出ます。--strip-trailing-cr で同じになりました。このページのツールは、改行コードだけの違いを「違いはありません」と判定しました。
Q. 何行まで比べられますか。
ツールは5,000行までです。手元では5,000行で10行の変更なら0.1秒以内に結果が出ました。それより長い文章は diff・git diff を使います。
Q. diff の「-」と「+」はどちらが新しいほうですか。+ が新しいほう(変更後)、- が元のほう(変更前)です。diff -u 元 新 の順に書いたときの意味で、順番を逆にすると記号も逆になります。
Q. @@ -1,4 +1,4 @@ の数字は何ですか。
「変更前の1行目から4行分」と「変更後の1行目から4行分」を、このハンクで示しているという意味です。
Q. Excel で2つの列を比べるには。
同じかどうかだけなら =EXACT(A1,B1) が使えます。大文字と小文字は区別され、書式の違いは無視されます。違う所を見るには、その行をツールに貼ります。
Q. 「変更」と「追加・削除」の分かれ方が diff と違うのはなぜですか。
diff は削除と追加が続く所を位置の順に並べますが、このツールは似た行どうしを組にして「変更」にするためです。行を足し引きした数の合計は同じになります。
Q. 全角空白を無視して比べるには。
ツールなら「空白の違いを無視」か「全角・半角の英数字を同じとみなす」で消えました。GNU diff と git diff の -w では消えなかったため、比べる前に置き換えます。
まとめ
この節では、テキスト比較の要点が5つに分かります。
- テキスト比較は、共通部分を最大にして残りを削除・追加とみなす作業です。このページのツールは行で比べ、似た行を組にして、行の中の違う文字まで色を付けます。
- diff の記号は、
-(変更前だけ)・+(変更後だけ)・@@(ハンクの行番号)を押さえれば読めます。 - 「同じなのに違う」は、改行コード・BOM・空白・NBSP・ゼロ幅スペース・NFD が原因です。無視の設定で消えないものは、cat -A や Python で文字を確かめます。
- 日本語の文の中の違いは、
git diff --word-diff-regex=.で文字単位に出せます。空白区切りの--word-diffでは行全体が1語になります。 - パッチとして渡すなら diff -u・git diff、Word の文書なら[比較]、5,001行以上なら diff を使います。
参考・出典
この節では、記事で確かめた公式の資料が分かります(確認日 2026年11月7日)。
- GNU diffutils マニュアル:https://www.gnu.org/software/diffutils/manual/
- Git 公式ドキュメント git-diff:https://git-scm.com/docs/git-diff
- Python 公式ドキュメント difflib:https://docs.python.org/ja/3/library/difflib.html
- Microsoft Learn「fc」:https://learn.microsoft.com/ja-jp/windows-server/administration/windows-commands/fc
- Visual Studio Code「Command Line Interface」:https://code.visualstudio.com/docs/configure/command-line
- Visual Studio Code「User Interface」:https://code.visualstudio.com/docs/getstarted/userinterface
- Microsoft サポート(Word の法的ブラックラインでの文書の比較):https://support.microsoft.com/ja-jp/office/dbfc7351-4022-43a2-a0c4-54d1898702a0
- Microsoft サポート「EXACT 関数」:https://support.microsoft.com/ja-jp/office/exact-関数-d3087698-fc15-4a15-9631-12575cf29926
- Eugene W. Myers「An O(ND) Difference Algorithm and Its Variations」(Algorithmica, 1986)
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「テキスト比較(差分チェック)|2つの文章の違いを色分け・diffの読み方」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。