Python - ความแตกต่างระหว่างสองสตริง


89

ฉันต้องการเก็บคำจำนวนมากไว้ในรายการ คำเหล่านี้หลายคำคล้ายกันมาก เช่นฉันมีคำafrykanerskojęzycznyหลายคำเช่นafrykanerskojęzycznym, ,afrykanerskojęzyczni nieafrykanerskojęzyczniอะไรคือโซลูชันที่มีประสิทธิภาพ (เร็วและให้ขนาด diff เล็ก ๆ ) เพื่อค้นหาความแตกต่างระหว่างสองสตริงและเรียกคืนสตริงที่สองจากอันแรกและค่าต่าง


1
"คืนค่าสตริงที่สองจากสตริงแรกและแตกต่าง"
jrd1

2
ฉันเชื่อว่าเขาหมายถึง "ทำให้สตริงที่สองเหมือนกับสตริงแรก"
Elias Benevedes

1
@EliasBenevedes เป๊ะ :).
user2626682

1
คุณกำลังมองหาสิ่งที่ชอบdifflib? ถ้าเป็นเช่นนั้นให้ดูเช่นstackoverflow.com/questions/774316/…
torek

คำตอบ:


113

คุณสามารถใช้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 หลามมีเพื่อให้โมดูลที่มีประโยชน์มากมาย ดูเหมือนว่าฉันจะเรียนรู้สิ่งใหม่ ๆ ในแต่ละวัน
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

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
นี่เป็นเพียงสิ่งที่ฉันเป็น Googling หนึ่งทราบอย่างรวดเร็ว @ 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

4
นอกจากนี้ยังอาจเป็นประโยชน์ในการแสดงผลลัพธ์ของคำสั่งของคุณ: >>> output_list; # result #['- b', '+ a', '+ m']
bballdave025

2
if not li.startswith(' ')เทียบเท่าของif li[0] != ' 'บางคนอาจพบว่ามันชัดเจนกว่า หรือแม้กระทั่งif item.startswith(('-', '+', ))
dmmfll

@DMfll Downvote. รายการไม่มีstartswith()ใน python3.7.4
Nathan

3

คุณสามารถดูโมดูล regex (ส่วนที่คลุมเครือ) ฉันไม่รู้ว่าคุณจะได้รับความแตกต่างที่แท้จริงหรือไม่ แต่อย่างน้อยคุณสามารถระบุจำนวนการเปลี่ยนแปลงประเภทต่างๆที่อนุญาตเช่นแทรกลบและการแทนที่:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.