在Python的字符串中查找字符串的多次出现


79

如何在Python的字符串中找到一个字符串的多次出现?考虑一下:

>>> text = "Allowed Hello Hollow"
>>> text.find("ll")
1
>>> 

因此,第一次出现ll是在预期的1。我如何找到它的下一次出现?

相同问题对列表有效。考虑:

>>> x = ['ll', 'ok', 'll']

如何找到所有ll带有它们的索引?


3
>>> text.count(“ ll”)
blackappy

2
@blackappy,此计数发生次数,不对它们进行本地化
pcko1

Answers:


120

使用正则表达式,您可以re.finditer用来查找所有(不重叠)事件:

>>> import re
>>> text = 'Allowed Hello Hollow'
>>> for m in re.finditer('ll', text):
         print('ll found', m.start(), m.end())

ll found 1 3
ll found 10 12
ll found 16 18

另外,如果您不希望使用正则表达式,也可以重复使用str.find来获取下一个索引:

>>> text = 'Allowed Hello Hollow'
>>> index = 0
>>> while index < len(text):
        index = text.find('ll', index)
        if index == -1:
            break
        print('ll found at', index)
        index += 2 # +2 because len('ll') == 2

ll found at  1
ll found at  10
ll found at  16

这也适用于列表和其他序列。


1
不使用正则表达式就没有办法吗?
user225312 2010年

1
并不是说我有任何问题,只是好奇。
user225312 2010年

2
清单没有find。但是,它的工作原理与index,你只需要except ValueError而不是用于测试-1
aaronasterling

@Aaron:我指的是基本概念,当然您必须对列表进行一些修改(例如,index += 1改为)。

4
现在您已经提到了整个过程index += 2,如果将其应用于字符串“ lllll”,它将丢失四分之二的“ ll”。最好也坚持index += 1弦乐。
aaronasterling 2010年

30

我想你要找的是 string.count

"Allowed Hello Hollow".count('ll')
>>> 3

希望这对您有帮助。
注意:仅捕获不重叠的事件


哇谢谢你。这是一个非常简单的工作答案
Derrick

25

对于列表示例,请使用以下理解:

>>> l = ['ll', 'xx', 'll']
>>> print [n for (n, e) in enumerate(l) if e == 'll']
[0, 2]

对于字符串类似:

>>> text = "Allowed Hello Hollow"
>>> print [n for n in xrange(len(text)) if text.find('ll', n) == n]
[1, 10, 16]

这将列出相邻的“ ll”游程,可能不是您想要的:

>>> text = 'Alllowed Hello Holllow'
>>> print [n for n in xrange(len(text)) if text.find('ll', n) == n]
[1, 2, 11, 17, 18]

哇,我喜欢这个。谢谢。太棒了。
user225312

5
这是极其低效的。
2014年

1
@Clément发布了一个更有效的示例
sirvon

@Clémentprint [如果text [n-1:n] =='ll',则在xrange(len(text))中为n表示n]
Stephen

我的意思是:如果text [n:n + 2] =='ll'],则打印[在xrange(len(text))中为n表示n]
Stephen

14

FWIW,以下是一些非RE替代方案,我认为这些方案poke的解决方案更为整洁。

第一次使用str.index和检查ValueError

def findall(sub, string):
    """
    >>> text = "Allowed Hello Hollow"
    >>> tuple(findall('ll', text))
    (1, 10, 16)
    """
    index = 0 - len(sub)
    try:
        while True:
            index = string.index(sub, index + len(sub))
            yield index
    except ValueError:
        pass

第二测试用途str.find和检查的前哨-1通过使用iter

def findall_iter(sub, string):
    """
    >>> text = "Allowed Hello Hollow"
    >>> tuple(findall_iter('ll', text))
    (1, 10, 16)
    """
    def next_index(length):
        index = 0 - length
        while True:
            index = string.find(sub, index + length)
            yield index
    return iter(next_index(len(sub)).next, -1)

要将这些函数中的任何一个应用于列表,元组或其他可迭代的字符串,可以使用一个更高级别的函数(该函数将一个函数作为其参数之一),如下所示:

def findall_each(findall, sub, strings):
    """
    >>> texts = ("fail", "dolly the llama", "Hello", "Hollow", "not ok")
    >>> list(findall_each(findall, 'll', texts))
    [(), (2, 10), (2,), (2,), ()]
    >>> texts = ("parallellized", "illegally", "dillydallying", "hillbillies")
    >>> list(findall_each(findall_iter, 'll', texts))
    [(4, 7), (1, 6), (2, 7), (2, 6)]
    """
    return (tuple(findall(sub, string)) for string in strings)

3

对于您的列表示例:

In [1]: x = ['ll','ok','ll']

In [2]: for idx, value in enumerate(x):
   ...:     if value == 'll':
   ...:         print idx, value       
0 ll
2 ll

如果要包含“ ll”的列表中的所有项目,也可以这样做。

In [3]: x = ['Allowed','Hello','World','Hollow']

In [4]: for idx, value in enumerate(x):
   ...:     if 'll' in value:
   ...:         print idx, value
   ...:         
   ...:         
0 Allowed
1 Hello
3 Hollow

2
>>> for n,c in enumerate(text):
...   try:
...     if c+text[n+1] == "ll": print n
...   except: pass
...
1
10
16

1

一般而言,这是编程的全新内容,并且可以通过在线教程进行学习。我也被要求这样做,但只能使用到目前为止所学的方法(基本上是字符串和循环)。不知道这是否在这里增加了任何价值,我知道这不是您要怎么做,但是我可以将其用于此工作:

needle = input()
haystack = input()
counter = 0
n=-1
for i in range (n+1,len(haystack)+1):
   for j in range(n+1,len(haystack)+1):
      n=-1
      if needle != haystack[i:j]:
         n = n+1
         continue
      if needle == haystack[i:j]:
         counter = counter + 1
print (counter)

1

此版本的字符串长度应该是线性的,并且应该很好,只要序列不太重复即可(在这种情况下,您可以用while循环替换递归)。

def find_all(st, substr, start_pos=0, accum=[]):
    ix = st.find(substr, start_pos)
    if ix == -1:
        return accum
    return find_all(st, substr, start_pos=ix + 1, accum=accum + [ix])

bstpierre的列表理解是短序列的一个很好的解决方案,但是看起来具有二次复杂性,并且从未在我使用的长文本上完成。

findall_lc = lambda txt, substr: [n for n in xrange(len(txt))
                                   if txt.find(substr, n) == n]

对于非平凡长度的随机字符串,两个函数给出的结果相同:

import random, string; random.seed(0)
s = ''.join([random.choice(string.ascii_lowercase) for _ in range(100000)])

>>> find_all(s, 'th') == findall_lc(s, 'th')
True
>>> findall_lc(s, 'th')[:4]
[564, 818, 1872, 2470]

但是二次版本要慢300倍

%timeit find_all(s, 'th')
1000 loops, best of 3: 282 µs per loop

%timeit findall_lc(s, 'th')    
10 loops, best of 3: 92.3 ms per loop

0
#!/usr/local/bin python3
#-*- coding: utf-8 -*-

main_string = input()
sub_string = input()

count = counter = 0

for i in range(len(main_string)):
    if main_string[i] == sub_string[0]:
        k = i + 1
        for j in range(1, len(sub_string)):
            if k != len(main_string) and main_string[k] == sub_string[j]:
                count += 1
                k += 1
        if count == (len(sub_string) - 1):
            counter += 1
        count = 0

print(counter) 

此程序将计算所有子字符串的数量,即使它们不使用正则表达式也重叠了。但这是一个幼稚的实现,在最坏的情况下要获得更好的结果,建议使用后缀树,KMP以及其他字符串匹配的数据结构和算法。


0

这是我发现多个事件的功能。与此处的其他解决方案不同,它支持切片的可选start和end参数,就像str.index

def all_substring_indexes(string, substring, start=0, end=None):
    result = []
    new_start = start
    while True:
        try:
            index = string.index(substring, new_start, end)
        except ValueError:
            return result
        else:
            result.append(index)
            new_start = index + len(substring)

0

一个简单的迭代代码,该代码返回出现子字符串的索引列表。

        def allindices(string, sub):
           l=[]
           i = string.find(sub)
           while i >= 0:
              l.append(i)
              i = string.find(sub, i + 1)
           return l

0

您可以拆分以获取相对位置,然后将列表中的连续数字求和并同时添加(字符串长度*出现顺序)以获取所需的字符串索引。

>>> key = 'll'
>>> text = "Allowed Hello Hollow"
>>> x = [len(i) for i in text.split(key)[:-1]]
>>> [sum(x[:i+1]) + i*len(key) for i in range(len(x))]
[1, 10, 16]
>>> 

0

也许不是Pythonic,但更不言而喻。它返回单词在原始字符串中的位置。

def retrieve_occurences(sequence, word, result, base_counter):
     indx = sequence.find(word)
     if indx == -1:
         return result
     result.append(indx + base_counter)
     base_counter += indx + len(word)
     return retrieve_occurences(sequence[indx + len(word):], word, result, base_counter)

0

我认为无需测试文本的长度;继续寻找,直到找不到任何东西为止。像这样:

    >>> text = 'Allowed Hello Hollow'
    >>> place = 0
    >>> while text.find('ll', place) != -1:
            print('ll found at', text.find('ll', place))
            place = text.find('ll', place) + 2


    ll found at 1
    ll found at 10
    ll found at 16


0

不久前,我随机得到了这个主意。即使字符串重叠,也可以将While循环与字符串拼接和字符串搜索一起使用。

findin = "algorithm alma mater alison alternation alpines"
search = "al"
inx = 0
num_str = 0

while True:
    inx = findin.find(search)
    if inx == -1: #breaks before adding 1 to number of string
        break
    inx = inx + 1
    findin = findin[inx:] #to splice the 'unsearched' part of the string
    num_str = num_str + 1 #counts no. of string

if num_str != 0:
    print("There are ",num_str," ",search," in your string.")
else:
    print("There are no ",search," in your string.")

我是Python编程(实际上是任何语言的编程)的业余爱好者,并且不确定它可能还会遇到什么其他问题,但是我想它能正常工作吗?

我猜lower()也可以在需要的地方使用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.