Python - iki dizge arasındaki fark


89

Bir listede çok fazla kelime saklamak istiyorum. Bu kelimelerin çoğu birbirine çok benziyor. Mesela ben kelime var afrykanerskojęzycznyve benzeri kelimelerin çoğu afrykanerskojęzycznym, afrykanerskojęzyczni, nieafrykanerskojęzyczni. İki dizge arasındaki farkı bulmak ve ikinci dizeyi ilk diziden ve farktan geri yüklemek için etkili (hızlı ve küçük fark boyutu veren) çözüm nedir?


1
"İkinci dizeyi birinci dizeden ve farktan geri yükle" ile
jrd1

2
Sanırım "İkinci ipi birinciyle aynı yap" demek istiyor.
Elias Benevedes

1
@EliasBenevedes, tam olarak :).
user2626682

1
Gibi bir şey mi arıyorsunuz difflib? Öyleyse, bakınız, örneğin, stackoverflow.com/questions/774316/…
torek

Yanıtlar:


113

Bunu yapmak için difflib modülünde ndiff kullanabilirsiniz . Bir dizeyi başka bir dizgeye dönüştürmek için gerekli tüm bilgilere sahiptir.

Basit bir örnek:

import difflib

cases=[('afrykanerskojęzyczny', 'afrykanerskojęzycznym'),
       ('afrykanerskojęzyczni', 'nieafrykanerskojęzyczni'),
       ('afrykanerskojęzycznym', 'afrykanerskojęzyczny'),
       ('nieafrykanerskojęzyczni', 'afrykanerskojęzyczni'),
       ('nieafrynerskojęzyczni', 'afrykanerskojzyczni'),
       ('abcdefg','xac')] 

for a,b in cases:     
    print('{} => {}'.format(a,b))  
    for i,s in enumerate(difflib.ndiff(a, b)):
        if s[0]==' ': continue
        elif s[0]=='-':
            print(u'Delete "{}" from position {}'.format(s[-1],i))
        elif s[0]=='+':
            print(u'Add "{}" to position {}'.format(s[-1],i))    
    print()      

baskılar:

afrykanerskojęzyczny => afrykanerskojęzycznym
Add "m" to position 20

afrykanerskojęzyczni => nieafrykanerskojęzyczni
Add "n" to position 0
Add "i" to position 1
Add "e" to position 2

afrykanerskojęzycznym => afrykanerskojęzyczny
Delete "m" from position 20

nieafrykanerskojęzyczni => afrykanerskojęzyczni
Delete "n" from position 0
Delete "i" from position 1
Delete "e" from position 2

nieafrynerskojęzyczni => afrykanerskojzyczni
Delete "n" from position 0
Delete "i" from position 1
Delete "e" from position 2
Add "k" to position 7
Add "a" to position 8
Delete "ę" from position 16

abcdefg => xac
Add "x" to position 0
Delete "b" from position 2
Delete "d" from position 4
Delete "e" from position 5
Delete "f" from position 6
Delete "g" from position 7

14
+1 Python'da pek çok kullanışlı modül var. Görünüşe göre her gün yeni bir tane öğreniyorum.
arshajii

1
Bu, farkı manuel olarak aşmaktır; iki dizge arasındaki farklılığı geri yüklemek elbette difflib.restore
dawg

Teşekkürler! Ama bunun hafıza açısından verimli olup olmadığından emin değilim. list (difflib.ndiff ("afrykanerskojęzyczny", "nieafrykanerskojęzyczny")) ['+ n', '+ i', '+ e', 'a', 'f', 'r', 'y', 'k' , 'a', 'n', 'e', ​​'r', 's', 'k', 'o', 'j', 'ę', 'z', 'y', 'c', ' z ',' n ',' y ']
user2626682

ndiffbir jeneratör olduğundan bellek açısından oldukça verimlidir. Tek listtek oluşturulan karakter karşılaştırmalarını tam bir listeye dönüştüren onu çağırıyorsunuz . Onu çağırmasaydın, bir seferde sadece birkaç hafızan listolurdu.
dawg

1
Python 2'de de çalışıyor (benim için) Belirli bir kaynak ve belirli çıktıyla bir soru sormanızı öneririm. Yorumlarda hata ayıklayamıyorum ...
dawg

26

Ndiff cevabını beğendim, ancak hepsini sadece değişikliklerin olduğu bir listeye koymak isterseniz, şöyle bir şey yapabilirsiniz:

import difflib

case_a = 'afrykbnerskojęzyczny'
case_b = 'afrykanerskojęzycznym'

output_list = [li for li in difflib.ndiff(case_a, case_b) if li[0] != ' ']

3
Google'da bunun için çalışıyordum. Kısa bir not, @Eric, değişkenleriniz bugün gösterildiği gibi eşleşmiyor, 20180905. Ya 1) son satırı olarak değiştirin output_list = [li for li in list(difflib.ndiff(case_a,case_b)) if li[0] != ' ']ya da 2) Dize değişkenlerinin adlarını case_a -> ave olarak değiştirin case_b -> b. Şerefe!
bballdave025

4
Komutunuzun çıktısını göstermek de yararlı olabilir >>> output_list:; # sonuç #['- b', '+ a', '+ m']
bballdave025

2
if not li.startswith(' ')if li[0] != ' 'Bazılarının eşdeğeridir daha okunaklı bulabilir. Ya da hattaif item.startswith(('-', '+', ))
dmmfll

@DMfll Olumsuz oy. Listeler startswith()python itibariyle yok3.7.4
Nathan

3

Normal ifade modülüne (bulanık bölüm) bakabilirsiniz . Gerçek farklılıkları elde edip edemeyeceğinizi bilmiyorum, ancak en azından ekleme, silme ve değiştirme gibi izin verilen farklı türde değişiklik türlerini belirtebilirsiniz:

import regex
sequence = 'afrykanerskojezyczny'
queries = [ 'afrykanerskojezycznym', 'afrykanerskojezyczni', 
            'nieafrykanerskojezyczni' ]
for q in queries:
    m = regex.search(r'(%s){e<=2}'%q, sequence)
    print 'match' if m else 'nomatch'

3

İstediğiniz şey özel bir sıkıştırma şeklidir. xdelta3 bu özel sıkıştırma türü için tasarlandı ve bunun için bir python bağlaması var, ancak muhtemelen doğrudan zlib kullanmaktan kurtulabilirsiniz. Sen kullanmak isterdim zlib.compressobjve zlib.decompressobjbirlikte zdictörneğin sizin "temel kelime", parametre seti afrykanerskojęzyczny.

Uyarılar zdictyalnızca python 3.3 ve daha yüksek sürümlerde desteklenir ve tüm farklarınız için aynı "temel kelimeye" sahipseniz kodlamak en kolayıdır, ki bu istediğiniz şey olabilir veya olmayabilir.


-2

Yukarıdaki Orijinal Soru hakkındaki yorumumun cevabı, bana tüm istediği şeyin bu olduğunu düşündürüyor:

loopnum = 0
word = 'afrykanerskojęzyczny'
wordlist = ['afrykanerskojęzycznym','afrykanerskojęzyczni','nieafrykanerskojęzyczni']
for i in wordlist:
    wordlist[loopnum] = word
    loopnum += 1

Bu, aşağıdakileri yapacaktır:

Kelime listesindeki her değer için, kelime listesinin bu değerini orijinal koda ayarlayın.

Tek yapmanız gereken bu kodu kelime listesini değiştirmeniz gereken yere koymak, değiştirmeniz gereken kelimeleri kelime listesinde sakladığınızdan ve orijinal kelimenin doğru olduğundan emin olmaktır.

Bu yardımcı olur umarım!


Teşekkürler, ama aslında 'nieafrykanerskojęzyczni' gibi kelimeleri 'afrykanerskojęzyczny' ile benzerlik kullanarak verimli bir şekilde saklamak istiyorum.
user2626682
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.