これは私が望む動作です:
a: IGADKYFHARGNYDAA
c: KGADKYFHARGNYEAA
2 difference(s).
def diff_letters(a,b):
return sum ( a[i] != b[i] for i in range(len(a)) )
この例は、Python ソフトウェア バージョンとの相互運用性の問題に悩まされることなく、特定のケースで機能すると思います (2.7 にアップグレードしてください)。
a='IGADKYFHARGNYDAA'
b='KGADKYFHARGNYEAA'
u=zip(a,b)
d=dict(u)
x=[]
for i,j in d.items():
if i==j:
x.append('*')
else:
x.append(j)
print x
出力: ['*', 'E', '*', '*', 'K', '*', '*', '*', '*', '*']
いくつかの微調整で、あなたが望むものを手に入れることができます....それが役立つかどうか教えてください:-)
アップデート
これを使用することもできます:
a='IGADKYFHARGNYDAA'
b='KGADKYFHARGNYEAA'
u=zip(a,b)
for i,j in u:
if i==j:
print i,'--',j
else:
print i,' ',j
出力:
I K
G -- G
A -- A
D -- D
K -- K
Y -- Y
F -- F
H -- H
A -- A
R -- R
G -- G
N -- N
Y -- Y
D E
A -- A
A -- A
更新 2
次のようにコードを変更できます。
y=[]
counter=0
for i,j in u:
if i==j:
print i,'--',j
else:
y.append(j)
print i,' ',j
print '\n', y
print '\n Length = ',len(y)
出力:
I K
G -- G
A -- A
D -- D
K -- K
Y -- Y
F -- F
H -- H
A -- A
R -- R
G -- G
N -- N
Y -- Y
D E
A -- A
A X
['K', 'E', 'X']
Length = 3
|
文字をそれぞれ追加して、新しい文字列で結果を保存します。また、異なる文字ごとにゼロから始まる整数値を増やします。組み込みzip
関数を使用するかitertools.izip
、両方の文字列を同時に反復することができますが、後者は巨大な入力の場合に少しパフォーマンスが高くなります。文字列が同じサイズでない場合、反復は短い部分に対してのみ行われます。この場合、残りを不一致を示す文字で埋めることができます。
import itertools
def compare(string1, string2, no_match_c=' ', match_c='|'):
if len(string2) < len(string1):
string1, string2 = string2, string1
result = ''
n_diff = 0
for c1, c2 in itertools.izip(string1, string2):
if c1 == c2:
result += match_c
else:
result += no_match_c
n_diff += 1
delta = len(string2) - len(string1)
result += delta * no_match_c
n_diff += delta
return (result, n_diff)
上記の例とは少し異なるオプションを使用した簡単なテストを次に示します。結果の文字列がより長い文字列のサイズに拡張される方法をよりよく示すために、一致しない文字を示すためにアンダースコアを使用していることに注意してください。
def main():
string1 = 'IGADKYFHARGNYDAA AWOOH'
string2 = 'KGADKYFHARGNYEAA W'
result, n_diff = compare(string1, string2, no_match_c='_')
print "%d difference(s)." % n_diff
print string1
print result
print string2
main()
出力:
niklas@saphire:~/Desktop$ python foo.py
6 difference(s).
IGADKYFHARGNYDAA AWOOH
_||||||||||||_|||_|___
KGADKYFHARGNYEAA W
Python には優れたdifflib
があり、必要な機能を提供するはずです。
ドキュメントの使用例は次のとおりです。
import difflib # Works for python >= 2.1
>>> s = difflib.SequenceMatcher(lambda x: x == " ",
... "private Thread currentThread;",
... "private volatile Thread currentThread;")
>>> for block in s.get_matching_blocks():
... print "a[%d] and b[%d] match for %d elements" % block
a[0] and b[0] match for 8 elements
a[8] and b[17] match for 21 elements
a[29] and b[38] match for 0 elements
a = "IGADKYFHARGNYDAA"
b = "KGADKYFHARGNYEAAXXX"
match_pattern = zip(a, b) #give list of tuples (of letters at each index)
difference = sum (1 for e in zipped if e[0] != e[1]) #count tuples with non matching elements
difference = difference + abs(len(a) - len(b)) #in case the two string are of different lenght, we add the lenght difference
Niklas R からの回答は気に入っていますが、問題があります (期待に応じて)。次の 2 つのテスト ケースで回答を使用します。
print compare('berry','peach')
print compare('berry','cherry')
チェリーはモモよりもベリーに似ていると期待するのは当然かもしれません。それでも、berryとpeachの差が小さくなり、次にberryとcherryの差が小さくなります。
(' | ', 4) # berry, peach
(' | ', 5) # berry, cherry
これは、文字列が順方向よりも逆方向に似ている場合に発生します。Niklas R からの回答から回答を拡張するために、通常の (前方) 差分と逆文字列の差分との間の最小差分を返すヘルパー関数を追加できます。
def fuzzy_compare(string1, string2):
(fwd_result, fwd_diff) = compare(string1, string2)
(rev_result, rev_diff) = compare(string1[::-1], string2[::-1])
diff = min(fwd_diff, rev_diff)
return diff
次のテスト ケースを再度使用します。
print fuzzy_compare('berry','peach')
print fuzzy_compare('berry','cherry')
...そして、私たちは得ます
4 # berry, peach
2 # berry, cherry
私が言ったように、これはNiklas R からの答えを変更するのではなく、単に拡張するだけです.
単純な diff 関数を探しているだけの場合 (前述の落とし穴を考慮して)、次のようにします。
def diff(a, b):
delta = do_diff(a, b)
delta_rev = do_diff(a[::-1], b[::-1])
return min(delta, delta_rev)
def do_diff(a,b):
delta = 0
i = 0
while i < len(a) and i < len(b):
delta += a[i] != b[i]
i += 1
delta += len(a[i:]) + len(b[i:])
return delta
テストケース:
print diff('berry','peach')
print diff('berry','cherry')
最後に考慮すべき点は、異なる長さの単語を処理する場合の diff 関数自体です。次の 2 つのオプションがあります。
例えば:
使用できる最短の単語のみを考慮する場合:
def do_diff_shortest(a,b):
delta, i = 0, 0
if len(a) > len(b):
a, b = b, a
for i in range(len(a)):
delta += a[i] != b[i]
return delta
...反復回数は最短の単語によって決定され、それ以外はすべて無視されます。または、さまざまな長さを考慮することができます。
def do_diff_both(a, b):
delta, i = 0, 0
while i < len(a) and i < len(b):
delta += a[i] != b[i]
i += 1
delta += len(a[i:]) + len(b[i:])
return delta
この例では、残りの文字がカウントされ、差分値に追加されます。両方の機能をテストするには
print do_diff_shortest('apple','apples')
print do_diff_both('apple','apples')
出力します:
0 # Ignore extra characters belonging to longest word.
1 # Consider extra characters.