计算两个字符串的字母差异

时间:2012-09-01 10:11:24

标签: python

这是我想要的行为:

a: IGADKYFHARGNYDAA
c: KGADKYFHARGNYEAA
2 difference(s).

12 个答案:

答案 0 :(得分:13)

def diff_letters(a,b):
    return sum ( a[i] != b[i] for i in range(len(a)) )

答案 1 :(得分:9)

理论

  1. 同时迭代两个字符串并比较字符。
  2. 通过分别添加空格键或|字符,将结果存储为新字符串。此外,为每个不同的字符增加从零开始的整数值。
  3. 输出结果。
  4. 实施

    您可以使用内置的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
    

答案 2 :(得分:8)

我想这个例子在这个具体案例中对您有用而没有太多复杂性,并且您的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', '*', '*', '*', '*', '*']


几乎没有tewakings,你可以得到你想要的东西....告诉我它是否有帮助: - )


<强>更新

您也可以使用:

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

答案 3 :(得分:4)

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    

答案 4 :(得分:2)

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

答案 5 :(得分:1)

我没有看到有人使用reduce函数,因此我将包含一段我一直在使用的代码:

reduce(lambda x, y: x + 1 if y[0] != y[1] else x, zip(source, target), 0)

将为您提供sourcetarget

中不同字符的数量

答案 6 :(得分:0)

使用difflib.ndiff你可以用一个仍然可以理解的单行程来做到这一点:

>>> import difflib
>>> a = 'IGADKYFHARGNYDAA'
>>> c = 'KGADKYFHARGNYEAA'
>>> sum([i[0] != ' '  for i in difflib.ndiff(a, c)]) / 2
2

sum在这里工作,因为,有点True == 1False == 0

以下内容清楚地说明了发生了什么以及为什么需要/ 2

>>> [i for i in difflib.ndiff(a,c)]
['- I',
 '+ K',
 '  G',
 '  A',
 '  D',
 '  K',
 '  Y',
 '  F',
 '  H',
 '  A',
 '  R',
 '  G',
 '  N',
 '  Y',
 '- D',
 '+ E',
 '  A',
 '  A']

如果字符串的长度不同,这也很有效。

答案 7 :(得分:0)

循环遍历一个字符串时,创建一个计数器对象,用于标识每次迭代时所在的字母。然后使用此计数器作为索引来引用其他序列。

a = 'IGADKYFHARGNYDAA'
b = 'KGADKYFHARGNYEAA'

counter = 0
differences = 0
for i in a:
    if i != b[counter]:
        differences += 1
    counter += 1

在这里,每次我们按顺序看到一个字母a不同于序列b中相同位置的字母时,我们将“差异”加1。然后我们在进入下一个字母之前将1加到计数器上。

答案 8 :(得分:0)

我喜欢来自Niklas R的the answer,但它有一个问题(取决于您的期望)。使用以下两个测试用例的答案:

print compare('berry','peach')
print compare('berry','cherry')

我们可以合理地期望樱桃更类似于浆果而不是樱桃。然而,我们在 berry 之间获得较低的差异,然后 berry cherry

(' |   ', 4)  # berry, peach
('   |  ', 5) # berry, cherry

当字符串向后比向前更相似时会发生这种情况。为了扩展Niklas R的回答,我们可以添加一个辅助函数,它返回正常(前向)diff和反向字符串diff之间的最小差异:

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的答案。

如果您只是在寻找一个简单的差异函数(考虑到前面提到的问题),以下内容将会:

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函数本身。有两种选择:

  1. 将长度之间的差异视为差异字符。
  2. 忽略长度差异,只比较最短的单词。
  3. 例如:

      在考虑所有情况时,
    • 苹果苹果的差异为1 字符。
    • apple apples 的差异为0 只考虑最短的单词

    当只考虑我们可以使用的最短词时:

    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
    

    在此示例中,计算任何剩余字符并将其添加到diff值。测试两种功能

    print do_diff_shortest('apple','apples')
    print do_diff_both('apple','apples')
    

    将输出:

    0 # Ignore extra characters belonging to longest word.
    1 # Consider extra characters.
    

答案 9 :(得分:0)

以下是基于此处提供的解决方案比较两个字符串的类似问题的解决方案:   https://stackoverflow.com/a/12226960/3542145

由于itertools.izip在Python3中不适用于我,我找到了简单地使用zip函数的解决方案:https://stackoverflow.com/a/32303142/3542145

比较两个字符串的功能:

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 zip(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 = 'AAUAAA'
    string2 = 'AAUCAA'
    result, n_diff = compare(string1, string2, no_match_c='_')
    print("%d difference(s)." % n_diff)
    print(string1)
    print(result)
    print(string2)

main()

返回:

1 difference(s).
AAUAAA
|||_||
AAUCAA

答案 10 :(得分:0)

这是我的解决方案。这将比较两个字符串,无论您在A或B中放置什么都无所谓。

#Declare Variables
a='Here is my first string'
b='Here is my second string'
notTheSame=0
count=0

#Check which string is bigger and put the bigger string in C and smaller string in D
if len(a) >= len(b):
    c=a
    d=b
if len(b) > len(a):
    d=a
    c=b

#While the counter is less than the length of the longest string, compare each letter.
while count < len(c):
    if count == len(d):
        break
    if c[count] != d[count]:
        print(c[count] + " not equal to " + d[count])
        notTheSame = notTheSame + 1
    else:
        print(c[count] + " is equal to " + d[count])
    count=count+1

#the below output is a count of all the differences + the difference between the 2 strings
print("Number of Differences: " + str(len(c)-len(d)+notTheSame))

答案 11 :(得分:0)

diff = 0
for i, j in zip(a, b): 
    if i != j: diff += 1
print(diff)