Python-2つの文字列の違い


90

たくさんの単語をリストに保存したいのですが。これらの単語の多くは非常に似ています。たとえば、私は言葉を持っているafrykanerskojęzycznyし、言葉の多くが好きafrykanerskojęzycznymafrykanerskojęzyczninieafrykanerskojęzyczni。2つの文字列の違いを見つけ、最初の文字列とdiffから2番目の文字列を復元するための効果的な(高速で小さなdiffサイズを与える)ソリューションは何ですか?


1
「最初の文字列から2番目の文字列を復元してdiffする」
jrd1 2013

2
彼は「2番目の弦を最初の弦と同じにする」という意味だと思います。
エリアスベネベデス2013

1
@EliasBenevedes、正確に:)。
user2626682 2013

1
あなたはのようなものを探していdifflibますか?もしそうなら、例えば、stackoverflow.com
questions / 774316 /…を

回答:


113

これを行うには、difflibモジュールでndiffを使用できます。ある文字列を別の文字列に変換するために必要なすべての情報が含まれています。

簡単な例:

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()      

プリント:

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
+ 1Pythonには非常に多くの便利なモジュールがあります。私は毎日新しいものについて学んでいるようです。
arshajii 2013

1
これは、違いを手動でステップスルーしています。もちろん、2つの文字列の違いを復元するには、difflib.restoreを使用する
dawg 2013

ありがとう!しかし、これがメモリ効率が良いかどうかはわかりません。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 2013

ndiffはジェネレータであるため、メモリ効率が非常に高くなります。list個別に生成された文字比較をそれらの完全なリストに変換することを求めています。あなたがそれを呼び出さなかったならば、あなたは一度にほんの少ししか記憶にないでしょうlist
dawg 2013

1
Python 2でも動作します(私にとって)特定のソースと特定の出力で質問することをお勧めします。私は...コメントでデバッグすることはできません
仲の良い友達

26

私はndiffの答えが好きですが、すべてを変更のみのリストに吐き出したい場合は、次のようにすることができます。

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
これは私がグーグルしていたものです。1つの簡単なメモ@Eric、今日示されているように変数が一致しません、20180905。1)最後の行をにoutput_list = [li for li in list(difflib.ndiff(case_a,case_b)) if li[0] != ' ']変更するか、2)文字列変数の名前をcase_a -> aとに変更しますcase_b -> b。乾杯!
bballdave025 2018

4
コマンドの出力を表示することも役立つ場合があります>>> output_list。#result#['- b', '+ a', '+ m']
bballdave025 2018

2
if not li.startswith(' ')は、if li[0] != ' '一部の人と同等であり、より読みやすくなる場合があります。あるいはif item.startswith(('-', '+', ))
dmmfll

@DMfll反対票。リストにはstartswith()pythonの時点ではありません3.7.4
Nathan

3

正規表現モジュール(ファジーセクション)を調べることができます。実際の違いを取得できるかどうかはわかりませんが、少なくとも、挿入、削除、置換など、さまざまな種類の変更の許容数を指定できます。

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

あなたが求めているのは、特殊な形式の圧縮です。 xdelta3は、この特定の種類の圧縮用に設計されており、Pythonバインディングがありますが、おそらくzlibを直接使用することで回避できます。あなたは利用したいと思いますzlib.compressobjzlib.decompressobjしてzdict例えば、あなたの「基本語」、にパラメータセットafrykanerskojęzyczny

警告はPython3.3以降zdictでのみサポートされており、すべての差分に同じ「ベースワード」がある場合にコーディングするのが最も簡単です。これは、必要な場合とそうでない場合があります。


-2

元の質問に対する上記の私のコメントへの答えは、これが彼が望んでいるすべてであると私に思わせます:

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

これにより、次のことが行われます。

ワードリストのすべての値について、ワードリストのその値を元のコードに設定します。

あなたがしなければならないのは、あなたがワードリストを変更する必要がある場所にこのコードを置き、あなたが変更する必要のある単語をワードリストに保存し、元の単語が正しいことを確認することです。

お役に立てれば!


ありがとうございますが、実際には、「afrykanerskojęzyczny」との類似性を使用して、「nieafrykanerskojęzyczni」のような単語をメモリ効率の高い方法で保存したいと思います。
user2626682 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.