【问题标题】:String similarity in PythonPython中的字符串相似度
【发布时间】:2016-07-15 03:38:37
【问题描述】:

我正在尝试对 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,尽管我认为这可能会增加一些复杂性,我可以通过重构字符串来解决。

【问题讨论】:

  • 为什么不直接删除所有标点符号并进行比较呢?见stackoverflow.com/questions/265960/…
  • @Liongold 在我输入问题时突然想到,谢谢,我会看看链接
  • 所以即使The Title: The SubtitleTitle, The: Subtitle, The 也应该被视为相等?
  • @IronFist 是的,尽管我认为处理 The 可能比按原样比较它们更好
  • 试试fuzzywuzzy库

标签: python string-comparison


【解决方案1】:

我是一名 Ruby 程序员,因此没有使用 Python 的经验,但在 Ruby 中,使用 gem Levensthein 可以很快解决这样的问题。它会计算您需要在一个字符串上进行的编辑次数才能达到相同的字符串。

我看到还有一个 Python 等价物,所以看看 https://pypi.python.org/pypi/python-Levenshtein

【讨论】:

    【解决方案2】:

    您可以使用in 关键字。这不是相似性比较,而是做你想做的事:

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

    【讨论】:

      【解决方案3】:

      尝试替换字符然后检查相等性:

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

      【讨论】:

        【解决方案4】:

        您正在尝试做的事情已经在jellyfish 包中很好地实现了。

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

        【讨论】:

        • 谢谢 DevShark,我认为这与其他答案的一部分相结合将使我接近我希望的地方。
        • 太好了,很高兴它有帮助。
        【解决方案5】:

        这应该可行。 Python translate 可用于取出任何不同的字符。

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

        【讨论】:

          【解决方案6】:

          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
          

          【讨论】:

          • 谷歌“正则表达式”,你会发现更好的方法来实现这种方法。
          • @alexis...我当然知道re 解决方案,但我只是想把它作为最后的手段,以免使事情复杂化...无论如何...在我的意图中,我是使用我已经发布的re 研究另一种方式
          【解决方案7】:

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

          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 是您的朋友。

          【讨论】:

          • 非常翔实的答案,谢谢。显然这比我最初想象的要复杂得多。
          • 这很复杂,但如果您认为 Levenshtein 距离非常适合您的任务,您可以将其保留在此...
          【解决方案8】:

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

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

          【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-10-19
          • 2019-05-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-06
          • 1970-01-01
          • 2018-06-15
          相关资源
          最近更新 更多