この記事の目的
正解文字列と任意の文字列を1文字単位で比較し、消えた文字を赤文字で、増えた文字を黄色の背景色でprint出力する。
ページの最後にコード一覧があります。
実行環境
- python 3.9
解説
使用するのは標準モジュール difflib の Differ オブジェクトの compare メソッドです。
compare(a, b)
文字列からなる2つのシーケンスを比較し、差分(を表す文字列からなるシーケンス)を生成します。
各シーケンスの要素は、改行で終わる独立した単一行からなる文字列でなければなりません。そのようなシーケンスは、ファイル風オブジェクトの readlines() メソッドによって得ることができます。(得られる)差分は改行文字で終了する文字列のシーケンスとして得られ、ファイル風オブジェクトの writelines() メソッドによって出力できる形になっています。
返り値はgenerator。
import difflib
d = difflib.Differ()
a = "abcde"
b = "a ydef"
diffs = d.compare(a, b)
for diff in diffs:
print(diff)
実行結果はコードと文字からなります。
a
- b
- c
+
+ y
d
e
+ f
コード | 意味 |
---|---|
'-' |
この文字は文字列aにのみ存在する |
'+' |
この文字は文字列bにのみ存在する |
' ' |
この文字は共通 |
一方で、文字に色をつけるにはエスケープシーケンスを使って、「色を付けるコード」+文章+「色付け終了コード」をprint文で出力します。
例えば、赤字で出力すると以下のような感じにします。
color_dic = {
'red':'\033[31m',
'yellow':'\033[43m',
'end':'\033[0m'
}
print(color_dic['red'] + 'サンプルです' + color_dic['end'])
色つけ終了コードをつけ忘れると、最後の文字まで指定コードの色に染まるのでお気をつけください。
表題の内容を実現するには、compareメソッドの返り値を差分コードに応じて色分けします。
今回は、正解文字列と対照文字列を比較したときに、消えた文字は赤文字で、増えた文字は黄背景で、変化のない文字はそのままprintすることにします。
コード一覧
import difflib
def print_diff_hl(ground_truth, target):
"""
文字列の差異をハイライト表示する
"""
color_dic = {
'red':'\033[31m',
'yellow':'\033[43m',
'end':'\033[0m'
}
d = difflib.Differ()
diffs = d.compare(ground_truth, target)
result = ''
for diff in diffs:
status, _, character = list(diff)
if status == '-':
character = color_dic['red'] + character + color_dic['end']
elif status == '+':
character = color_dic['yellow'] + character + color_dic['end']
else:
pass
result += character
print(f"ground truth : {ground_truth}")
print(f"target string: {target}")
print(f"diff result : {result}")
ground_truth = "abcde"
target = "a ydef"
print_diff_hl(ground_truth, target)
終わりに
長い文字列の比較には適しませんが、tipsの一つとなれば幸いです。