web-dev-qa-db-fra.com

Python - différence entre deux chaînes

Je voudrais stocker beaucoup de mots dans une liste. Beaucoup de ces mots sont très similaires. Par exemple, j'ai Word afrykanerskojęzyczny et beaucoup de mots comme afrykanerskojęzycznym, afrykanerskojęzyczni, nieafrykanerskojęzyczni. Quelle est la solution efficace (rapide et donnant une petite taille de diff) pour trouver la différence entre deux chaînes et restaurer la deuxième chaîne à partir de la première et de la diff?

58
user2626682

Pour ce faire, vous pouvez utiliser ndiff dans le module difflib. Il contient toutes les informations nécessaires pour convertir une chaîne en une autre chaîne.

Un exemple simple:

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

impressions:

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
81
dawg

J'aime la réponse ndiff, mais si vous voulez tout cracher dans une liste des changements seulement, vous pouvez faire quelque chose comme:

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] != ' ']
13
Eric

Ce que vous demandez, c'est une forme de compression spécialisée. xdelta a été conçu pour ce type de compression, et il existe une liaison python), mais vous pourriez probablement vous en tirer en utilisant directement zlib. Vous voudriez utilisation zlib.compressobj et zlib.decompressobj avec le paramètre zdict défini sur votre "mot de base", par exemple. afrykanerskojęzyczny.

Les mises en garde sont zdict n'est supporté que dans python 3.3 et supérieur, et il est plus facile de coder si vous avez le même "mot de base" pour tous vos diffs, qui peuvent ou non sois qui tu veux.

3
Craig Silverstein

Vous pouvez regarder dans le module regex (la section floue). Je ne sais pas si vous pouvez obtenir les différences réelles, mais vous pouvez au moins spécifier le nombre autorisé de types de modifications différents, tels que l'insertion, la suppression et les substitutions:

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'
2
perreal