Python Funktion um Strings zu vergleichen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
sprudel
User
Beiträge: 248
Registriert: Donnerstag 8. März 2007, 17:12

Dienstag 20. März 2007, 15:50

Hallo.
Gibt es in Python irgendeine Funktion mit der man vergleichen kann, wieviele Buchstaben in 2 Strings übereinstimmen und das in Prozent ausgeben?

Ich stell mir das so vor, wie bei der PHP Funktion similar_text
BlackJack

Dienstag 20. März 2007, 17:00

Dazu müsste man wissen was die PHP-Funktion macht.

Zwei Ansätze die mir einfallen würden wären der `difflib.SequenceMatcher` oder selber etwas schreiben.

Code: Alles auswählen

from difflib import SequenceMatcher

def get_similarity_ratio(seq_a, seq_b):
    return SequenceMatcher(a=seq_a, b=seq_b).ratio()
Wie sich das Verhältnis genau berechnet bitte in der Dokumentation nachlesen. :-)

Selbstgebastelt:

Code: Alles auswählen

from __future__ import division
from itertools import izip

def get_similarity_ratio(seq_a, seq_b):
    total = max(map(len, (seq_a, seq_b)))
    if total == 0:
        return 1
    matches = sum(int(a == b) for a, b in izip(seq_a, seq_b))
    return matches / total
Die Funktion hält sich im wesentlichen an Deine Beschreibung indem sie das Verhältnis von übereinstimmenden Elementen zur Gesamtanzahl berechnet. Nichtvorhandene Elemente, also wenn die Sequenzen unterschiedlich lang sind, zählen als Unterschiede.
sprudel
User
Beiträge: 248
Registriert: Donnerstag 8. März 2007, 17:12

Dienstag 20. März 2007, 17:48

Hi. Erstmal: vielen Dank für deine kompetente Hilfe.

Da ich leider grad nicht die Möglichkeit hab es auszuprobieren, hab ich noch folgende Frage: Gibt deine Funktion/die andere es in einer Prozentzahl aus? Das ist nämlich für mich Vorraussetzung.

Vielen Dank
R00TKiD
User
Beiträge: 6
Registriert: Dienstag 13. März 2007, 09:43

Dienstag 20. März 2007, 17:59

sprudel hat geschrieben:in einer Prozentzahl
return str(matches / total * 100) + "%"

;)
sprudel
User
Beiträge: 248
Registriert: Donnerstag 8. März 2007, 17:12

Dienstag 20. März 2007, 18:03

Hallo. Vielen Dank für eure Ergebnise. Hab jetzt doch noch kurz Zeit gefunden es zu testen.

Code: Alles auswählen

from difflib import SequenceMatcher

def get_similarity_ratio(seq_a, seq_b):
    return SequenceMatcher(a=seq_a, b=seq_b).ratio()
Das ist einfach die perfekte Lösung.

Ich musste nur noch ein *100 dahinter machen, und schon hab ich die Prozentzahl. Vielen Vielen Dank. Ihr habt mir riesig geholfen.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Mittwoch 21. März 2007, 13:00

R00TKiD hat geschrieben: return str(matches / total * 100) + "%"
Das ergibt allerdings immer 0%, da die Division zweier Integer auf einen Integer abrundet.

Abhilfe schafft
(a) Konvertieren von (mind.) einem Operanden in float oder
(b) from __future__ import division
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
sprudel
User
Beiträge: 248
Registriert: Donnerstag 8. März 2007, 17:12

Freitag 23. März 2007, 12:44

Hi, ich bin es nochmal. Ich habe jetzt seltsamerweise das Problem dass wenn ich die Strings vertausche, es unterschiedliche Ergebnise gibt. Woran könnte es liegen? Es ist mir nämlich wichtig dass die Reihenfolge irrelevant ist.
BlackJack

Freitag 23. März 2007, 19:17

Das wird wohl an dem Algorithmus vom `SequenceMatcher` liegen. Meine kleine Funktion da oben sollte das Problem nicht haben. Oder Du sortierst die beiden Zeichenketten, so dass sie immer in der gleichen Reihenfolge an den `SequenceMatcher` übergeben werden.
sprudel
User
Beiträge: 248
Registriert: Donnerstag 8. März 2007, 17:12

Freitag 23. März 2007, 19:40

Hi BlackJack. Wie muss ich die denn sortieren? Das klingt nämlich am einfachsten. Bei deiner Funktion muss ich leeider so viel importieren. Deswegen will ich mir die nur als letzte Möglichkeit aufheben
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Freitag 23. März 2007, 19:43

sprudel hat geschrieben:Wie muss ich die denn sortieren?
Einfach nur beide Strings sortieren?

Code: Alles auswählen

string = 'Das ist ein String'
string_sortiert = ''.join(sorted(string))
sprudel hat geschrieben:Bei deiner Funktion muss ich leeider so viel importieren. Deswegen will ich mir die nur als letzte Möglichkeit aufheben
Das erste ist nur ein Pseudo-Import den du weglassen kannst wenn du den Code umschreibst und das zweite ein Import aus der Stdlib, dessen Dauer überhaupt schwer zu messen sein wird.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
sprudel
User
Beiträge: 248
Registriert: Donnerstag 8. März 2007, 17:12

Freitag 23. März 2007, 20:07

Hi. Gibt es auch eine Möglichkeit es so zu machen dass die Einträge in einer Liste (Dictionary oder was auch immer... ich kann diese Dinger vom Namen her immer noch nicht unterscheiden) ausgegeben werden? Also beide in einem, aber alphabetisch geordnet. So wäre ein vertauschen nicht schlimm, da sie sowieso sortiert werden.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Freitag 23. März 2007, 20:13

sprudel hat geschrieben:Hi. Gibt es auch eine Möglichkeit es so zu machen dass die Einträge in einer Liste (Dictionary oder was auch immer... ich kann diese Dinger vom Namen her immer noch nicht unterscheiden) ausgegeben werden?
Dictionary ist aber radikal unterschiedlich von einer Liste. Schon allein dadurch dass ein Dictionary von Definition aus unsortiert ist.
sprudel hat geschrieben:Also beide in einem, aber alphabetisch geordnet. So wäre ein vertauschen nicht schlimm, da sie sowieso sortiert werden.
Ganz ehrlich - ich verstehe irgendwie nicht auf was du hinaus willst.

Code: Alles auswählen

string_dict = {'string1' : 'Vergleich1', 'string2' : 'Vergleich2'}
So, und nun? :?:
My god, it's full of CARs! | Leonidasvoice vs Modvoice
sprudel
User
Beiträge: 248
Registriert: Donnerstag 8. März 2007, 17:12

Freitag 23. März 2007, 20:16

Ich versuche es nochmal vom Anfang an zu erklären.
Ich möchte für meinen kleinen Bruder einen sogenannten Love-O-Meter machen, wie ihn Jamba auch anbietet. Dort kann man zwei Namen eingeben und dann wird angezeigt wie sehr sie zusammenpassen.

Es ist nur leider im Moment so dass wenn man die Namen vertauscht, ein anderes Ergebnis herauskommt. Deswegen dachte ich mir ich ordne die Ergebnisse alphabetisch. So wäre ein vertauschen nicht schlimm. Die Frage ist nur: wie mache ich das?
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Freitag 23. März 2007, 20:28

sprudel hat geschrieben:So wäre ein vertauschen nicht schlimm. Die Frage ist nur: wie mache ich das?
Achso, jetzt ist klar.

Das geht etwa so:

Code: Alles auswählen

In [45]: namen = ['Lukas', 'Anna']
In [46]: namen.sort()
In [47]: namen
Out[47]: ['Anna', 'Lukas']
Auf die einzelnen Elemente kannst du dann per namen[0] und namen[1] zugreifen, die kannst du dann dem an ``get_similarity_ratio()`` & Co. weiterleiten. Oder noch direkter mit dem *-Operator:

Code: Alles auswählen

In [49]: from difflib import SequenceMatcher
In [51]: def get_similarity_percent(seq_a, seq_b):
    return SequenceMatcher(a=seq_a, b=seq_b).ratio() * 100
In [56]: get_similarity_percent(*namen)
Out[56]: 22.222222222222221
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Antworten