0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Python で差分を色付きで表示する方法

0
Posted at

テキストの差分を unified 形式 + 色付きで表示したいとき、diff --color -u a.txt b.txt で表示できます (Windows 環境でも Git Bash なら動作します)。

が、Python での処理中のテキスト同士の差分を表示したい場合には、subprocess.run(['diff', ...]) と外部に投げるのは面倒 / Python と連携しにくいです。

そこで、Python 標準ライブラリの difflib.unified_diff を使うと unified 形式の差分を生成できます。ただし、色は自分で付ける必要があります。colorama パッケージを使う方法と、使わない方法を記します。いずれも下図のようになります。

image.png

colorama を使って差分に色を付ける方法

colorama パッケージを利用した方法の例は以下です。最初の @ で始まる行 (差分のあるブロックの範囲を示す箇所) に遭遇したら水色にします。その後は、- で始まる行を赤に、+ で始まる行を緑にする指示も追加します (これらの指示を最初から追加すると比較するファイル名にも色が付くため)。

from colorama import Fore

def color_diff(diff):
    color = {'@': Fore.CYAN + '@'}
    for line in diff:
        yield color.get(line[0], line[0]) + line[1:] + Fore.RESET
        if line[0] == '@':
            color.update({'-': Fore.RED + '-', '+': Fore.GREEN + '+'})

以下のように 2 ファイルの差分を表示できます。

from pathlib import Path
import difflib
from colorama import Fore

def color_diff(diff):
    color = {'@': Fore.CYAN + '@'}
    for line in diff:
        yield color.get(line[0], line[0]) + line[1:] + Fore.RESET
        if line[0] == '@':
            color.update({'-': Fore.RED + '-', '+': Fore.GREEN + '+'})

if __name__ == '__main__':
    path_a, path_b = 'a.txt', 'b.txt'
    diff = difflib.unified_diff(
        Path(path_a).read_text(encoding='utf8').splitlines(),
        Path(path_b).read_text(encoding='utf8').splitlines(),
        fromfile=path_a, tofile=path_b, lineterm='',
    )
    for line in color_diff(diff):
        print(line)

colorama を使わないで差分に色を付ける方法

colorama を使わない方法は以下のように ANSI エスケープシーケンスを直接記述します。colorama を使う場合と挙動は同じです。colorama パッケージを使った方が可読性・可搬性のうえでよいですが、標準ライブラリで済ませたい場合はこちらの方法を使用します (私の手元の Windows 環境の Git Bash / コマンドプロンプトでもこれで動作します)。

def color_diff(diff):
    ansi = {'@': '\033[36m@'}
    for line in diff:
        yield ansi.get(line[0], line[0]) + line[1:] + '\033[0m'
        if line[0] == '@':
            ansi.update({'-': '\033[31m-', '+': '\033[32m+'})

参考文献

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?