【问题标题】:Basic indexing recurrences of a substring within a string (python)字符串中子字符串的基本索引重复(python)
【发布时间】:2011-10-22 16:41:28
【问题描述】:

我正在自学基本编程。
一个简单的项目是查找字符串中子字符串的重复索引。例如,在字符串“abcdefdef”和子字符串“def”中,我希望输出为 3 和 6。我编写了一些代码,但没有得到我想要的答案。以下是我写的


注意:我知道可能有更简单的方法来产生结果,利用语言的内置功能/包,例如正则表达式。我也知道我的方法可能不是最佳算法。不过,此时,我只是在寻求有关修复以下逻辑的建议,而不是使用更惯用的方法。

import string

def MIT(String, substring): # "String" is the main string I'm searching within
    String_list = list(String)
    substring_list = list(substring)
    i = 0
    j = 0
    counter = 0
    results = []
    while i < (len(String)-1):
        if [j] == [i]:
            j = j + 1
            i = i + 1
            counter  = counter + 1
            if counter == len(substring):
                results.append([i - len(substring)+1])
                counter = 0
                j = 0
                i = i+1
        else:
            counter = 0
            j = 0
            i = i+1
    print results
    return

我的推理是这样的。我将字符串和子字符串变成一个列表。这允许对字符串中的每个字母进行索引。我设置 i 和 j = 0——这将分别是我在字符串和子字符串索引中的第一个值。我还有一个新变量 counter,我将其设置为 0。基本上,我使用 counter 来计算位置 [i] 中的字母等于位置 [j] 中的元素的次数。如果 counter 等于子字符串的长度,那么我知道 [i - len(substring) + 1] 是我的子字符串开始的位置,所以我将它添加到名为 results 的列表中。然后我重置 counter 和 j 并继续搜索更多子字符串。

我知道代码很笨拙,但我认为我仍然应该能够得到答案。相反,我得到:

>>> MIT("abcdefghi", "def")
[[3]]
>>> MIT("abcdefghi", "efg")
[[3]]
>>> MIT("abcdefghi", "b")
[[1]]
>>> MIT("abcdefghi", "k")
[[1]]

有什么想法吗?

【问题讨论】:

  • 这对codereview.stackexchange.com来说似乎是个好问题
  • @Gerrat codereview 仅适用于 working 代码 - 但自 2011 年以来规则可能已更改。

标签: python list indexing


【解决方案1】:

正则表达式模块 (re) 更适合这项任务。

很好的参考: http://docs.python.org/howto/regex.html

还有: http://docs.python.org/library/re.html

编辑: 更“手动”的方式可能是使用切片

s = len(String)
l = len(substring)
for i in range(s-l+1):
    if String[i:i+l] == substring:
        pass #add to results or whatever

【讨论】:

  • string.index,但我认为重点是练习,而不是答案。
  • 谢谢,但是如果我想迭代地做呢?我确信你的方法有效,但我想学习如何以“硬”的方式做到这一点
【解决方案2】:

我不清楚你是想学习一些好的字符串搜索算法,还是在 Python 中学习一种简单的方法。如果是后者,那么string.find 就是你的朋友。类似的东西

def find_all_indexes(needle, haystack):
    """Find the index for the beginning of each occurrence of ``needle`` in ``haystack``. Overlaps are allowed."""
    indexes = []
    last_index = haystack.find(needle)
    while -1 != last_index:
        indexes.append(last_index)
        last_index = haystack.find(needle, last_index + 1)
    return indexes


if __name__ == '__main__':
    print find_all_indexes('is', 'This is my string.')

虽然这是一种非常幼稚的方法,但应该很容易理解。

如果您正在寻找使用更少标准库的东西(实际上会教您实现库时使用的相当常见的算法),您可以尝试实现Boyer-Moore string search algorithm

【讨论】:

    【解决方案3】:

    主要/主要问题如下:

    • 为了比较,使用:if String[i] == substring[j]
    • 您在找到匹配项时将 i 递增两次,然后删除第二次递增。
    • 循环应该一直到while i &lt; len(String):

    当然它不会找到重叠的匹配项(例如:MIT("aaa", "aa")

    有一些小“问题”,它不是真正的pythonic,不需要构建列表,如果写成i += 1,增量会更清晰,一个有用的函数应该返回值而不是打印它们等等......

    如果您想要正确且快速的代码,请查看经典算法书:http://www.amazon.com/Introduction-Algorithms-Thomas-H-Cormen/dp/0262033844。它有一整章是关于字符串搜索的。

    如果您想要一个 pythonic 解决方案而不实现整个事情,请检查其他答案。

    【讨论】:

    • 您可以查找 KMP 以获得经典的、非平凡的字符串搜索算法。
    • 是的,书上有。但维基百科也有一些不错但非常复杂的解决方案,书中没有介绍(例如:高效匹配多个字符串)
    【解决方案4】:

    首先,我在您的代码中添加了一些 cmets 以提供一些提示

    import string
    
    def MIT(String, substring): 
        String_list = list(String)  # this doesn't need to be done; you can index strings
        substring_list = list(substring)
        i = 0
        j = 0
        counter = 0
        results = []
        while i < (len(String)-1):   
            if [j] == [i]:   # here you're comparing two, one-item lists. you must do substring[j] and substring[i]
                j = j + 1
                i = i + 1
                counter  = counter + 1
                if counter == len(substring):
                    results.append([i - len(substring)+1]) # remove the brackets; append doesn't require them
                    counter = 0
                    j = 0
                    i = i+1 # remove this 
            else:
                counter = 0
                j = 0
                i = i+1
    print results
    return
    

    以下是不使用内置库等的方法:

    def MIT(fullstring, substring):
        results = []
        sub_len = len(substring)
        for i in range(len(fullstring)):  # range returns a list of values from 0 to (len(fullstring) - 1)
            if fullstring[i:i+sub_len] == substring: # this is slice notation; it means take characters i up to (but not including) i + the length of th substring
                results.append(i)
        return results
    

    【讨论】:

    【解决方案5】:

    为了找到字符串中子字符串的位置,这个算法会做:

    def posnof_substring(string,sub_string):
    l=len(sub_string)
    for i in range(len(string)-len(sub_string)+1):
        if(string[i:i+len(sub_string)] == sub_string ):      
            posn=i+1
    return posn           
    

    我自己检查了这个算法,它奏效了!

    【讨论】:

    • ... 它起作用了 - 不,它没有,结果差了一个。
    【解决方案6】:

    基于@Hank Gay 的回答。使用正则表达式并添加一个选项来搜索单词。

    
        def find_all(item, text, as_word=False):
            indexes = []
            re_term = rf'\b{item}\b' if as_word else item
            for r in re.finditer(re_term, text.lower()):
                indexes.append(r.start())
            return indexes
        
        if __name__ == '__main__':
            word = 'for'
            text = 'Now for a bold step forward.'
            print(find_all(word, text), find_all(word, text, as_word=True))
    
    

    【讨论】:

      猜你喜欢
      • 2019-06-03
      • 1970-01-01
      • 2017-02-15
      • 1970-01-01
      • 1970-01-01
      • 2022-08-19
      • 2014-03-17
      • 2010-12-15
      • 2016-03-23
      相关资源
      最近更新 更多