2016-03-27 21 views
5

Próbuję wykonać porównanie ciągów w języku Python. Moje struny zawierać tytuły, które mogą być skonstruowane wiele różnych sposobów:Podobieństwo ciągów w języku Python

'Title' 
'Title: Subtitle' 
'Title - Subtitle' 
'Title, Subtitle' 
'Title Subtitle' 

jest to możliwe do zrobienia porównania podobieństwa w Pythonie, aby mógł on stwierdzić, że match('Title: Subtitle', 'Title - Subtitle') = True? (lub jakkolwiek byłby skonstruowany)

Zasadniczo próbuję ustalić, czy są one tego samego tytułu, nawet jeśli podział jest inny.

if 'Title: Subtitle' == 'Title - Subtitle': 
    match = 'True' 
else: 
    match = 'False' 

Są też takie, które mogą być przechowywane jako The Title: The Subtitle lub Title, The: Subtitle, The chociaż myślę, że może dodać trochę złożoności pewnie mógłby obejść rekonstrukcji łańcucha.

+1

Dlaczego po prostu nie usuwać wszystkich znaków interpunkcyjnych i nie porównywać? Zobacz http://stackoverflow.com/questions/265960/best-way-to-strip-punctuation-from-a-string-in-python –

+0

@Liongold, który przyszedł mi do głowy podczas pisania pytania, dzięki Rzucę okiem na link – Midavalo

+0

Więc nawet "Tytuł: Podtytuł" i "Tytuł, The: Subtitle, The" powinny być również uważane za równe? –

Odpowiedz

10

Co próbujesz już zostało bardzo dobrze zaimplementowane w pakiecie jellyfish.

>>> import jellyfish 
>>> jellyfish.levenshtein_distance('jellyfish', 'smellyfish') 
2 
+0

Dziękuję DevShark, myślę, że to w połączeniu z częściami innych odpowiedzi zbliży mnie do siebie do miejsca, w którym miałem nadzieję. – Midavalo

+0

Świetnie, cieszę się, że pomaga. – DevShark

1

Jestem programistą Ruby, więc nie mam doświadczenia z Pythonem, ale w Rubim taki problem zostałby szybko rozwiązany przy użyciu klejnotu Levensthein. Oblicza liczbę zmian, które należy wprowadzić w łańcuchu, aby uzyskać ten sam ciąg.

widzę istnieje odpowiednik Python również, więc spojrzeć na https://pypi.python.org/pypi/python-Levenshtein

3

Można użyć in słowa kluczowego. To nie jest porównanie podobieństwa, ale robi to, co chcesz:

s = "Title: Subtitle" 

if "Title" in s or "Subtitle" in s: 
    match = 'True' 
else: 
    match = 'False' 
2

spróbować wymienić znaków, a następnie sprawdzenie równości:

def match(str1, str2): 
    str1 = str1.replace(' -', '').replace(',', '').replace(':', '') 
    str2 = str2.replace(' -', '').replace(',', '').replace(':', '') 
    return str1 == str2 

>>> match('Title: Subtitle', 'Title - Subtitle') 
True 
>>> match('Title: Subtitle', 'Title, Subtitle') 
True 
>>> 
1

To powinno zadziałać. Python translate może być używany do usuwania dowolnych znaków.

titles = ['Title: Sub', 'Title Sub', 'Title - Sub'] 
s = ': -' 

if titles[1].translate(None, s) == titles[2].translate(None, s): 
    match = 'True' 
else 
    match = 'False' 
0

fnmatch.fnmatch może być również przydatny tutaj chociaż zaprojektowany dla Unix Filename dopasowywania, należy rozważyć następujące przykłady:

>>> from fnmatch import fnmatch 
>>> l 
['Title: Subtitle', 'Title - Subtitle', 'Title, Subtitle', 'Title Subtitle'] 
>>> 
>>> all(fnmatch(x, 'Title*Subtitle') for x in l) 
True 

Inną metodą, będzie sprawdzanie, czy wszystkie one dopasować re wzoru:

>>> import re 
>>> l 
['Title: Subtitle', 'Title - Subtitle', 'Title, Subtitle', 'Title Subtitle'] 
>>> all(re.search(r'^Title.*?Subtitle$', x) for x in l) 
True 
+0

Google "wyrażenie regularne", a znajdziesz znacznie lepsze sposoby na wdrożenie tego podejścia. – alexis

+0

@alexis ... Oczywiście, że wiem o rozwiązaniu 're', ale próbuję po prostu zostawić to w ostateczności, aby nie komplikować ... i tak ... w moim zamyśle pracowałem na alternatywny sposób używając' '' '' re' które już opublikuję –

2

Jeśli jedyną przeszkodą jest interpunkcja, problem jest banalny: po prostu odrzuć znaki inne niż słowa i porównaj pozostałe listy słów.

s1 = 'Title - Subtitle' 
toks1 = re.split(r"^\W+", s1) # keep just the words 
toks1 = [ w.lower() for w in toks1 ] 

Wrzuciłem w dolnej części, ponieważ może się różnić. Zastosuj to samo do każdego wejścia i porównaj listy.

Ale jak wskazujesz, mogą występować inne różnice. Jeśli twoje dane naprawdę składają się z tytułów (książek, filmów, artykułów naukowych), możesz zacząć od usuwania artykułów i wspólnych połączeń (tak zwane "stopwords"), tak jak robią to biblioteki. Np .: "Tytuł artykułu" zostaje usunięty do ["title", "article"]. Aby poradzić sobie z innymi możliwymi różnicami w porządku wyrazów, można zastosować tak zwane podejście "worka słów", powszechne w wyszukiwaniu informacji.Konwertuj listę tokenów do zestawu lub do słownika zliczeń słów dla przypadków, w których niektóre słowa występują wiele razy. Oto przykład, używając liczby słów i listy "stopword" nltk jako filtra.

import nltk 
from collections import Counter 
stopwords = set(nltk.corpus.stopwords.words("english")) 

toks1 = [ t for t in toks1 if t not in stopwords ] 
cnt1 = Counter(toks1) 
cnt2 = Counter(toks2) # Another title string, processed the same way 
if cnt1 == cnt2: 
    print("The two strings have exactly the same content words") 

Jeśli jest jeszcze więcej wariacji, niebo jest granicą. Przybliżone dopasowywanie tekstu jest tematem aktywnych badań z zastosowaniem w wyszukiwaniu informacji, wykrywaniem plagiatu, genetyką itp. Można sprawdzić, czy jeden tytuł jest podzbiorem drugiego (może ktoś pominął podtytuł). Możesz spróbować dopasować przez "edytuj odległość" (na przykład "odległość Levenshteina" wymienioną w kilku innych odpowiedziach), stosując ją albo do liter, albo do całych słów. Możesz wypróbować algorytmy wyszukiwania informacji, takie jak wynik TF-IDF. To tylko niektóre z rzeczy, które możesz wypróbować, więc poszukaj najprostszego rozwiązania, które spełni twoje zadanie. Google to twój przyjaciel.

+0

Bardzo pouczająca odpowiedź, dziękuję. Oczywiście jest to o wiele bardziej skomplikowane, niż sobie wyobrażałem. – Midavalo

+0

To jest skomplikowane, ale jeśli myślisz, że odległość Levenshteina jest odpowiednia dla twojego zadania, możesz po prostu to zostawić ... – alexis

4

Moduł standardowej biblioteki difflib zapewnia funkcję get_close_matches, która wykonuje dopasowanie rozmytego łańcucha.

>>> import difflib 
>>> difflib.get_close_matches('python', ['snakes', 'thon.py', 'pythin']) 
['pythin', 'thon.py'] # ordered by similarity score 
+0

difflib używa Ratcliff/Obershelp https://xlinux.nist.gov/dads/HTML/ratcliffObershelp .html, który w niektórych przypadkach może nie być tak dobry jak Levenshtein – wordsforthewise