3

我正在尝试查看一个字符串是否存在于另一个字符串中,而不使用 Python 的预定义函数,例如 find 和 index..

现在我的函数需要 2 个字符串作为参数,一个是我们要搜索的字符串,而另一个字符串是我们在第一个字符串中寻找的字符串。

如果第二个字符串存在于第一个字符串中,我希望我的函数返回它出现在第一个字符串中的所有位置。

现在,我的函数能够找到第一个匹配项并返回一个索引,但是我想找到多个匹配项,而不仅仅是第一个。

下面是我的代码:

def multi_find (s, r):

    s_len = len(s)
    r_len = len(r)

    if s_len < r_len:
        n = -1
    else:
        m = s_len - r_len
        n = -1  # assume r is not yet found in s
        i = 0

        while n == -1 and i < m:
            # search for r in s until not enough characters are left
            if s[i:i + r_len] == r:
                n = i
            else:
                i = i + 1
    print (n)

multi_find("abcdefabc. asdli! ndsf acba saa abe?", "abc")

现在,这将只输出“0”,因为那是 abc 首先出现的地方。我怎样才能让它返回“0”和“6”(第二次出现的开始),基本上在找到一个之后继续检查。

我正在考虑创建一个它发生的所有位置的列表,然后将 i 附加到该列表中,但是当我尝试这样做时,没有任何东西对我有用。

4

7 回答 7

8

你可以做:

>>> haystack = "abcdefabc. asdli! ndsf acba saa abe?"
>>> needle = "abc"
>>> for i, _ in enumerate(haystack):
...     if haystack[i:i + len(needle)] == needle:
...         print (i)
...
0
6
于 2013-11-07T17:37:25.997 回答
3

另一种使用方法regex

>>> import re
>>> haystack = "abcdefabc. asdli! ndsf acba saa abe?"
>>> needle = "abc"
>>> [m.start() for m in re.finditer(r'{}'.format(re.escape(needle)), haystack)]
[0, 6]

上述解决方案不适用于重叠的子字符串 例如'aa'. 'aaaa'因此,如果您还想找到重叠的匹配项,那么:

>>> haystack = "bobob"
>>> needle = "bob"
>>> [m.start() for m in re.finditer(r'(?={})'.format(re.escape(needle)), haystack)]
[0, 2]
于 2013-11-07T17:47:16.237 回答
1

@Jacob,我希望你会发现这个很短但仍然很容易理解。

def multi_find(s, r):
    return [pos for pos in range(len(s)) if s.startswith(r,pos)]
于 2013-11-07T19:16:54.087 回答
1
def multi_find(s, r):

    s_len = len(s)
    r_len = len(r)

    _complete = []

    if s_len < r_len:
        n = -1
    else:

        for i in xrange(s_len):
            # search for r in s until not enough characters are left
            if s[i:i + r_len] == r:
                _complete.append(i)
            else:
                i = i + 1
    print(_complete)

multi_find("abcdefabc. asdli! ndsf abc saa abe?", "abc")
于 2013-11-07T17:43:46.350 回答
1

可能最好的方法是继续调用 find 函数(这也是最快的)

def multifind(string, value, start = 0, stop = None):
    values = []
    while True:
        found = string.find(value, start, stop)
        if found == -1:
            break
        values.append(found)
        start = found + 1
    return values

print multifind('hello abc abc', 'abc')

输出:

[6, 10]
于 2013-11-07T18:00:55.043 回答
1
def multi_find (s, r):
    s_len = len(s)
    r_len = len(r)
    n = [] # assume r is not yet found in s

    if s_len >= r_len:
        m = s_len - r_len
        i = 0

        while i < m:
            # search for r in s until not enough characters are left
            if s[i:i + r_len] == r:
                n.append(i)
            i = i + 1
    print (n)

multi_find("abcdefabc. asdli! ndsf acba saa abe?", "abc")

几乎只需将 n 替换为列表,这样您就可以在找到它们时继续为其添加值。即使找到匹配项,您也需要增加 i ,它会永远卡在循环中,除非您有 while n == -1 约束,一旦找到匹配项就停止。

于 2013-11-07T17:51:27.517 回答
0

注意:我认为这里的这个答案仍然是一个很好的“教学答案”,我在这个线程的其他地方提交了一个更好的解决方案,没有递归。

def multi_find(s, r, start=0):
    if start >= len(s): 
        return []
    if s.startswith(r, start):
        return [start] + multi_find(s, r, start+1)
    else:
        return multi_find(s, r, start+1)

这允许您传递一个可选start位置来开始搜索s

这个解决方案是递归的,它可能是最快的实现,也可能不是最快的实现,但它是正确的,我相信它使代码很容易识别每个位置的三种可能性中的每一种s

  1. 结束s
  2. 找到另一个r
  3. 没有找到另一个r
于 2013-11-07T18:10:11.930 回答