Python - різниця між двома рядками


87

Я хотів би зберегти багато слів у списку. Багато з цих слів дуже схожі. Наприклад , у мене є слово , afrykanerskojęzycznyі багато хто з таких слів , як afrykanerskojęzycznym, afrykanerskojęzyczni, nieafrykanerskojęzyczni. Яке ефективне (швидке та дає невеликий розмір різниці) рішення, щоб знайти різницю між двома рядками та відновити другий рядок з першого та diff?


1
Що ви маєте на увазі під словом "відновити другий рядок з першого та змінити"?
jrd1

2
Я вважаю, що він має на увазі "Зробити другий рядок таким же, як і перший".
Elias Benevedes

1
@EliasBenevedes, саме :).
user2626682

1
Ви шукаєте щось на зразок difflib? Якщо так, дивіться, наприклад, stackoverflow.com/questions/774316/…
torek

Відповіді:


109

Для цього ви можете використовувати ndiff у модулі difflib. Він має всю інформацію, необхідну для перетворення одного рядка в інший рядок.

Простий приклад:

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
+1 Python має так багато корисних модулів. Здається, що нового я дізнаюся щодня.
arshajii

1
Це проходить через різницю вручну; відновити різне між двома рядками, звичайно, набагато простіше за допомогою difflib.restore
dawg

Дякую! Але я не впевнений, чи це ефективно для пам'яті. список (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

ndiffє генератором, тому він досить ефективний для пам'яті. Ви закликаєте listйого, який перетворює індивідуально згенеровані порівняння символів у їх повний список. У вас було б лише кілька пам’яті за раз, якби ви їх не закликали list.
dawg

1
Працює і над Python 2 (для мене), я б запропонував задати питання з конкретним джерелом та конкретним результатом. Я не можу налагоджувати коментарі ...
dawg

24

Мені подобається відповідь 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
Це саме те, заради чого я гуглив. Одне коротке зауваження, @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,

3
Також може бути корисно показати вихідні дані вашої команди >>> output_list:; # результат #['- b', '+ a', '+ m']
bballdave025

2
if not li.startswith(' ')є eqivalent з if li[0] != ' 'Деякі можуть знайти більш розбірливими. Або навітьif item.startswith(('-', '+', ))
dmmfll

@DMfll Проголосувати проти. Списки не мають startswith()станом на python3.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.compressobjі zlib.decompressobjз zdictпараметром, встановленим на "базове слово", наприклад afrykanerskojęzyczny.

Застереження zdictпідтримуються лише в python 3.3 та новіших версіях, і найпростіше кодувати, якщо у вас є одне і те ж "базове слово" для всіх ваших відмінностей, яке може бути, а може і не тим, що ви хочете.


-2

Відповідь на мій коментар вище до Оригінального запитання змушує мене думати, що це все, що він хоче:

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

Це зробить наступне:

Для кожного значення в списку слів встановіть для цього значення список слів оригінальний код.

Все, що вам потрібно зробити, - це помістити цей фрагмент коду туди, де вам потрібно змінити список слів, переконавшись, що ви зберігаєте слова, які потрібно змінити, у списку слів, і щоб оригінальне слово було правильним.

Сподіваюся, це допомагає!


Дякую, але насправді я хотів би зберігати такі слова, як "nieafrykanerskojęzyczni", ефективною пам'яттю, використовуючи подібність до "afrykanerskojęzyczny".
user2626682
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.