2016-03-27 86 views
5

我想在Python中对字符串进行比较。我的字符串包含标题可以构造多种不同的方式:Python中的字符串相似性

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

是否有可能做相似性比较的Python,以便它能够确定match('Title: Subtitle', 'Title - Subtitle') = True? (或将它构建)

基本上我试图确定他们是否是相同的标题,即使分裂是不同的。

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

也有一些虽然我认为这可能会增加一点复杂性我大概可以得到解决通过重建字符串可能被存储为The Title: The SubtitleTitle, The: Subtitle, The

+1

为什么不只是删除所有的标点符号然后比较呢?查看http://stackoverflow.com/questions/265960/best-way-to-strip-punctuation-from-a-string-in-python –

+0

@Liongold在我输入问题的时候发生在我身上,谢谢我我们来看看链接 – Midavalo

+0

因此,即使是“The Title:The Subtitle”和“Title,The:Subtitle,The'也应该被认为是平等的吗? –

回答

10

你想什么do已经在jellyfish包中得到了很好的实施。

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

谢谢DevShark,我认为这与其他答案的部分结合会让我接近到我希望的地方。 – Midavalo

+0

太棒了,很高兴它有帮助。 – DevShark

1

我是一个Ruby程序员,所以没有Python经验,但在Ruby中这样的问题很快就可以通过使用gem Levensthein来解决。它计算您需要在字符串中进行编辑以获得相同字符串的编辑数量。

我看到有一个Python也相当的,所以看看https://pypi.python.org/pypi/python-Levenshtein

3

可以使用in关键字。它不是一个类似的比较,但你想要做什么:

s = "Title: Subtitle" 

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

尝试更换字符,然后检查平等:

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

这应该有效。 Python翻译可以用来取出任何不同的字符。

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也能得心应手这里虽然专为Unix的文件名匹配,考虑下面的例子:

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

另一种方法,将被检查,如果它们都匹配re模式:

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

谷歌“正则表达式”,你会发现更好的方法来实现这种方法。 – alexis

+0

@alexis ...当然,我知道're'解决方案,但我只是想把它作为最后的手段不要使事情复杂......无论如何......在我的意图中,我正在使用'重新'我已经发布它 –

2

如果唯一的障碍是标点符号,则问题很简单:只需丢弃非单词字符并比较剩余的单词列表。

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

我扔了低档,因为这可能会有所不同。对每个输入应用相同的内容并比较列表。

但正如您指出的那样,可能会有其他差异。如果您的数据真的包含标题(书籍,电影,科学文章),您可以从删除文章和常见连接词(所谓的“停用词”)开始,就像图书馆一样。例如,“文章的标题”被精简到["title", "article"]。要处理其他可能的词序差异,可以使用所谓的“词袋”方法,这在信息检索中很常见。将标记列表转换为集合,或转换为字数统计字典,以查看某些字词多次出现的情况。下面是一个例子,使用字数和nltk的“停用词”列表作为过滤器。

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

如果还有更多的变化,天空是极限。近似文本匹配是一个积极研究与信息检索,剽窃检测,遗传学等应用主题的话题。您可以检查一个标题是否是另一个标题的一个子集(可能有人遗漏了字幕)。您可以尝试通过“编辑距离”(例如其他几个答案中提到的“Levenshtein距离”)进行匹配,将其应用于字母或整个单词。你可以尝试像TF-IDF分数这样的信息检索算法。这些只是你可以尝试的一些事情,所以寻找最适合你的最简单的解决方案。 Google是你的朋友。

+0

非常丰富的答案,谢谢。很显然,这是我想象的更复杂。 – Midavalo

+0

这很复杂,但是如果你认为Levenshtein距离适合你的任务,你可以把它留在那... – alexis

4

标准库的difflib模块提供了一个函数get_close_matches,它可以进行模糊字符串匹配。

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

difflib正在使用Ratcliff/Obershelp https://xlinux.nist.gov/dads/HTML/ratcliffObershelp .html在某些情况下可能不如Levenshtein – wordsforthewise