【问题标题】:Overlapping count of substring in a string in PythonPython中字符串中子字符串的重叠计数
【发布时间】:2015-11-23 20:03:28
【问题描述】:

我想查找字符串中子字符串的所有计数(重叠和非重叠)。 我找到了两个答案,其中一个是使用正则表达式,这不是我的意图,另一个比我需要的效率低得多。 我需要类似的东西:

'ababaa'.count('aba') == 2

str.count() 只计算简单的子字符串。我该怎么办?

【问题讨论】:

标签: python string count substring


【解决方案1】:
def sliding(a, n):
    return (a[i:i+n] for i in xrange(len(a) - n + 1))

def substring_count(a, b):
    return sum(s == b for s in sliding(a, len(b)))

assert list(sliding('abcde', 3)) == ['abc', 'bcd', 'cde']    
assert substring_count('ababaa', 'aba') == 2

【讨论】:

  • 时间复杂度是多少?
  • 对于固定的 |b|,它是 O(|a|)。作为两者的函数 |a|和 |b|,我必须多想……可能是 O(|a| * |b|)。可能能够给出更好的界限,但我猜你只关心 |b| 的情况
  • 嗯,效率很高。谢谢@ChrisMartin
【解决方案2】:

这能解决问题吗?

def count(string, substring):
    n = len(substring)
    cnt = 0
    for i in range(len(string) - n):
        if string[i:i+n] == substring:
            cnt += 1
    return cnt

print count('ababaa', 'aba') # 2

我不知道是否有更有效的解决方案,但这应该可行。

【讨论】:

  • 确实如此,但重要的是效率。如果迭代是我必须做的全部,我本可以做到的,事实上,我已经做到了,但我需要更少的时间,因为我正在解决的问题包含非常大的字符串,我不认为迭代会工作的。
  • @lavee_singh 这与我的算法本质上是相同的,只是用程序而不是函数式编写。相同的复杂性。
  • 抱歉,有很多不同之处。您通过创建列表和迭代器来使用,这基本上比生成器慢。尝试在()和[]中标出区别,这个区别很大。
【解决方案3】:
count = len(set([string.find('aba',x) for x in range(len(string)) if string.find('aba',x) >= 0]))

【讨论】:

    【解决方案4】:

    在这里,使用re.finditer() 是实现您想要的最佳方式。

    import re 
    
    def get_substring_count(s, sub_s):
        return sum(1 for m in re.finditer('(?=%s)' % sub_s, s))
    
    get_substring_count('ababaa', 'aba')
    # 2 as response
    

    【讨论】:

    • 时间复杂度是多少?
    • 很好,但我有一个时间复杂度更高的解决方案。但这也很好。
    【解决方案5】:

    这是一个你可以使用的函数:

    def count(haystack, needle):
        return len([x for x in [haystack[i:j+1] for i in xrange(len(haystack)) for j in xrange(i,len(haystack))] if x == needle])
    

    然后:

    >>> count("ababaa", "aba")
    2
    

    【讨论】:

      【解决方案6】:

      遍历切片字符串

      def count_substring(string, sub_string):
          l = len(sub_string)
          n = len(string)
          count = sum(1 for i in range(n-l+1) if string[i:i+l].count(sub_string)>0 )
          return count
      

      【讨论】:

        【解决方案7】:

        另一种考虑的方法是利用Counter 容器。虽然接受的答案对于较短的字符串最快,但如果您在长字符串中搜索相对较短的子字符串,则 Counter 方法开始占据优势。此外,如果您需要重构它以针对同一个主字符串执行多个子字符串计数查询,那么 Counter 方法开始看起来更具吸引力

        例如,使用 timeit 搜索长度 = 3 的子字符串给了我以下结果;

        主字符串长度/接受的答案/计数器方法

        6 个字符 / 4.1us / 7.4us

        50 个字符 / 24.4us / 25us

        150 个字符 / 70.7us / 64.9us

        1500 个字符 / 723us / 614us

        from collections import Counter
        
        def count_w_overlap(search_string, main_string):
            #Split up main_string into all possible overlap possibilities
            search_len = len(search_string)
            candidates = [main_string[i:i+search_len] for i in range(0, len(main_string) - search_len + 1)]
            #Create the Counter container
            freq_count = Counter(candidates)
            return freq_count[search_string]
        

        【讨论】:

          【解决方案8】:

          蛮力的方法只是

          n = len(needle)
          count = sum(haystack[i:i+n] == needle for i in range(len(haystack)-n+1))
          

          (这是有效的,因为在 Python 中 TrueFalse 在大多数用途(包括数学)中等同于数字 10

          可以使用正则表达式

          count = len(re.findall(needle[:1]+"(?="+re.escape(needle[1:])+")",
                                 haystack))
          

          (即使用a(?=ba) 而不是aba 也可以找到重叠的匹配项)

          【讨论】:

            猜你喜欢
            • 2014-11-01
            • 1970-01-01
            • 2018-08-23
            • 1970-01-01
            • 1970-01-01
            • 2020-06-02
            • 2017-08-05
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多