あなたのケースでは、一般的なケースに特化しています。difflib に物を渡す前に、フロートを含む行を検出して個別に処理する必要があります。これは基本的なアプローチです。デルタやコンテキスト行などを生成したい場合は、これに基づいて構築できます。float を文字列ではなく実際の float としてあいまい比較する方が簡単であることに注意してください (ただし、列ごとに異なるコードを記述して、1-e4 の後の文字を無視することもできます)。
import re
float_pat = re.compile('([+-]?\d*\.\d*)')
def fuzzydiffer(line1,line2):
"""Perform fuzzy-diff on floats, else normal diff."""
floats1 = float_pat.findall(line1)
if not floats1:
pass # run your usual diff()
else:
floats2 = float_pat.findall(line2)
for (f1,f2) in zip(floats1,floats2):
(col1,col2) = line1.index(f1),line2.index(f2)
if not fuzzy_float_cmp(f1,f2):
print "Lines mismatch at col %d", col1, line1, line2
continue
# or use a list comprehension like all(fuzzy_float_cmp(f1,f2) for f1,f2 in zip(float_pat.findall(line1),float_pat.findall(line2)))
#return match
def fuzzy_float_cmp(f1,f2,epsilon=1e-4):
"""Fuzzy-compare two strings representing floats."""
float1,float2 = float(f1),float(f2)
return (abs(float1-float2) < epsilon)
いくつかのテスト:
fuzzydiffer('text: 558.113509766 +23477547.6407 -0.867086648057 0.009291785451',
'text: 558.11351 +23477547.6406 -0.86708665 0.009292000001')
おまけとして、列の差分を強調するバージョンを次に示します。
import re
float_pat = re.compile('([+-]?\d*\.\d*)')
def fuzzydiffer(line1,line2):
"""Perform fuzzy-diff on floats, else normal diff."""
floats1 = float_pat.findall(line1)
if not floats1:
pass # run your usual diff()
else:
match = True
coldiffs1 = ' '*len(line1)
coldiffs2 = ' '*len(line2)
floats2 = float_pat.findall(line2)
for (f1,f2) in zip(floats1,floats2):
(col1s,col2s) = line1.index(f1),line2.index(f2)
col1e = col1s + len(f1)
col2e = col2s + len(f2)
if not fuzzy_float_cmp(f1,f2):
match = False
#print 'Lines mismatch:'
coldiffs1 = coldiffs1[:col1s] + ('v'*len(f1)) + coldiffs1[col1e:]
coldiffs2 = coldiffs2[:col2s] + ('^'*len(f2)) + coldiffs2[col2e:]
#continue # if you only need to highlight first mismatch
if not match:
print 'Lines mismatch:'
print ' ', coldiffs1
print '< ', line1
print '> ', line2
print ' ', coldiffs2
# or use a list comprehension like
# all()
#return True
def fuzzy_float_cmp(f1,f2,epsilon=1e-4):
"""Fuzzy-compare two strings representing floats."""
print "Comparing:", f1, f2
float1,float2 = float(f1),float(f2)
return (abs(float1-float2) < epsilon)