架空の商談メモ4版を並べたら、v10より後ろにv9が来た。この順で「最新版」を選ぶ処理は危ない。
僕なら版番号を整数に直します。v9とv10を選び、回答期限の変更1か所を取り出せました。
Pythonで版番号を取り出す
sorted()で名前を並べると、共通部分の次の文字で順序が決まります。v10の数字は1から始まるので、v2やv9より前。版の順番には使えません。
名前は商談メモ_v1.txtの形式。番号は1以上、先頭のゼロは禁止。欠番があれば、残った中で番号が大きい2版を選びます。
「最終」「最終修正」は、どちらが後か名前だけでは決まりません。
4版から直前との差分を出す
CPython 3.14.6で実行済み。下をmemo_diff.pyに保存し、python3 memo_diff.pyで動きます。見本はメモリ内に置きます。
import re
from difflib import unified_diff
def version(name):
m = re.fullmatch(r"商談メモ_v([1-9][0-9]*)\.txt", name)
if m is None:
raise ValueError(f"版番号を読めません: {name}")
return int(m[1])
def compare(files):
names = sorted(files, key=version)
if len(names) < 2:
raise ValueError("比較には2版以上必要です")
old, new = names[-2:]
diff = list(unified_diff(
files[old].splitlines(), files[new].splitlines(),
fromfile=old, tofile=new, n=0, lineterm="",
))
return names, diff
files = {
"商談メモ_v1.txt": "回答期限: 未定\n担当: 佐藤\n",
"商談メモ_v2.txt": "回答期限: 9月25日\n担当: 佐藤\n",
"商談メモ_v9.txt": "回答期限: 9月25日\n担当: 田中\n",
"商談メモ_v10.txt": "回答期限: 9月28日\n担当: 田中\n",
}
names, diff = compare(files)
assert sorted(files)[-1] == "商談メモ_v9.txt"
assert [version(n) for n in names] == [1, 2, 9, 10]
assert diff == [
"--- 商談メモ_v9.txt", "+++ 商談メモ_v10.txt",
"@@ -1 +1 @@", "-回答期限: 9月25日", "+回答期限: 9月28日",
]
print("\n".join(diff))
出力は5行。3つのassertも通りました。
--- 商談メモ_v9.txt
+++ 商談メモ_v10.txt
@@ -1 +1 @@
-回答期限: 9月25日
+回答期限: 9月28日
---と+++は版の名前、@@ -1 +1 @@は両方の1行目を示します。-が変更前、+が変更後。2行で1か所の書き換えです。
担当者はv2からv9で変わっています。今回比べたv9とv10では同じなので出ません。直前からの変更だけを読むなら、この切り分けが助かります。
行を整えすぎると変更が消える
n=0で周辺の同じ行を省きます。splitlines()で行末を外したため、差分の見出しにも改行を足さないlineterm=""を指定。CPython同梱のdifflib.unified_diffのdocstringと実装で確認しました。
LFとCRLF、末尾改行の有無は区別しません。空白の削除や本文の並べ替えはせず、字下げや行順の変更は残します。短いテキストメモ向けで、WordやPDFは直接読めません。
実ファイルでは、上のfiles = {以降を次に置き換えます。作業フォルダ内のmemosに、同じ商談のUTF-8テキストを2版以上入れます。
from pathlib import Path
files = {
p.name: p.read_text(encoding="utf-8-sig")
for p in Path("memos").glob("商談メモ_*") if p.is_file()
}
names, diff = compare(files)
print(f"比較: {names[-2]} → {names[-1]}")
print("\n".join(diff) if diff else "本文の差分なし")
商談メモ_最終.txtはValueErrorで止まります。黙って除外すると比較対象の抜けに気づけません。v01やバックアップ名の拒否も確認済みです。
桁が増えてもこの手順を使えます。ただし、最大の版が承認済みかは別に確認が必要です。送付前に直前との差分を出し、変更を読むところまで使う。参考になればストックで教えてください。
