Python - sự khác biệt giữa hai chuỗi


88

Tôi muốn lưu trữ nhiều từ trong một danh sách. Nhiều từ rất giống nhau. Ví dụ tôi có chữ afrykanerskojęzycznyvà rất nhiều những từ như afrykanerskojęzycznym, afrykanerskojęzyczni, nieafrykanerskojęzyczni. Giải pháp hiệu quả (nhanh chóng và cung cấp kích thước khác biệt nhỏ) để tìm sự khác biệt giữa hai chuỗi và khôi phục chuỗi thứ hai từ chuỗi đầu tiên và chuỗi khác là gì?


1
Ý bạn là gì khi "khôi phục chuỗi thứ hai từ chuỗi đầu tiên và khác biệt"?
jrd1

2
Tôi tin rằng ý của anh ấy là "Làm cho chuỗi thứ hai giống với chuỗi đầu tiên".
Elias Benevedes

1
@EliasBenevedes, chính xác :).
user2626682

1
Bạn đang tìm kiếm một cái gì đó giống như difflib? Nếu vậy, hãy xem, ví dụ như, stackoverflow.com/questions/774316/...
torek

Câu trả lời:


109

Bạn có thể sử dụng ndiff trong mô-đun difflib để thực hiện việc này. Nó có tất cả thông tin cần thiết để chuyển đổi một chuỗi này thành một chuỗi khác.

Một ví dụ đơn giản:

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

bản in:

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 có rất nhiều mô-đun hữu ích. Có vẻ như tôi học về một cái mới mỗi ngày.
arshajii

1
Đây là bước qua sự khác biệt theo cách thủ công; khôi phục khác nhau giữa hai chuỗi, tất nhiên, là dễ dàng hơn nhiều với difflib.restore
Dawg

Cảm ơn! Nhưng tôi không chắc liệu điều này có hiệu quả về bộ nhớ hay không. 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 ']
dùng2626682 28/07/13

ndifflà một máy phát điện nên nó khá hiệu quả về bộ nhớ. Bạn đang kêu gọi listnó biến các phép so sánh ký tự được tạo riêng lẻ thành một danh sách đầy đủ của chúng. Bạn sẽ chỉ có một vài trong bộ nhớ tại một thời điểm nếu bạn không gọi listnó.
dawg

1
Hoạt động trên Python 2 (đối với tôi), tôi khuyên bạn nên đặt một câu hỏi với nguồn cụ thể và đầu ra cụ thể. Tôi không thể gỡ lỗi trong nhận xét ...
dawg

25

Tôi thích câu trả lời của ndiff, nhưng nếu bạn muốn đưa tất cả vào danh sách chỉ những thay đổi, bạn có thể làm một số điều như:

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
Đây chỉ là những gì tôi đã sử dụng Google. Một lưu ý nhanh, @Eric, các biến của bạn không khớp như được hiển thị ngày hôm nay, 20180905. Hoặc 1) thay đổi dòng cuối cùng thành output_list = [li for li in list(difflib.ndiff(case_a,case_b)) if li[0] != ' ']hoặc 2) Thay đổi tên của các biến chuỗi thành case_a -> acase_b -> b. Chúc mừng!
bballdave025

4
Nó cũng có thể hữu ích để hiển thị đầu ra của lệnh của bạn: >>> output_list; # Kết quả #['- b', '+ a', '+ m']
bballdave025

2
if not li.startswith(' ')là đặc điểm của if li[0] != ' 'một số có thể thấy nó dễ đọc hơn. Hoặc thậm chíif item.startswith(('-', '+', ))
dmmfll

@DMfll Phản đối. Danh sách không có startswith()tính python3.7.4
Nathan

3

Bạn có thể xem xét mô-đun regex (phần mờ). Tôi không biết liệu bạn có thể nhận được sự khác biệt thực sự hay không, nhưng ít nhất bạn có thể chỉ định số lượng các loại thay đổi khác nhau được phép như chèn, xóa và thay thế:

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

Những gì bạn đang yêu cầu là một dạng nén chuyên biệt. xdelta3 được thiết kế cho loại nén cụ thể này và có một liên kết python cho nó, nhưng bạn có thể thoát khỏi việc sử dụng zlib trực tiếp. Bạn muốn sử dụng zlib.compressobjzlib.decompressobjvới zdicttham số được đặt thành "từ cơ sở" của bạn, ví dụ afrykanerskojęzyczny.

Cảnh báo zdictchỉ được hỗ trợ trong python 3.3 trở lên và dễ viết mã nhất nếu bạn có cùng một "từ cơ sở" cho tất cả các khác biệt của mình, có thể có hoặc không phải những gì bạn muốn.


-2

Câu trả lời cho nhận xét của tôi ở trên về Câu hỏi gốc khiến tôi nghĩ rằng đây là tất cả những gì anh ấy muốn:

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

Điều này sẽ làm như sau:

Đối với mọi giá trị trong danh sách từ, hãy đặt giá trị đó của danh sách từ thành mã gốc.

Tất cả những gì bạn phải làm là đặt đoạn mã này vào nơi bạn cần thay đổi danh sách từ, đảm bảo rằng bạn lưu trữ những từ bạn cần thay đổi trong danh sách từ và từ gốc là chính xác.

Hi vọng điêu nay co ich!


Cảm ơn, nhưng thực sự tôi muốn lưu trữ các từ như 'nieafrykanerskojęzyczni' theo cách hiệu quả về bộ nhớ, sử dụng tương tự như 'afrykanerskojęzyczny'.
user2626682
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.