返回

Python 中巧妙查找字符串中所有子字符串出现位置

python

如何在 Python 中查找字符串中所有子字符串出现的索引

在 Python 中处理字符串时,经常需要找出子字符串在字符串中出现的位置。为了满足这一需求,string 模块提供了两个有用的方法:find()rfind()。虽然这些方法很方便,但它们只能找到子字符串的第一个或最后一个出现位置。那么,我们如何查找所有出现的位置呢?本文将探讨 Python 中解决此问题的优雅方法。

目标:所有出现位置的索引列表

我们的目标是创建一个函数,该函数可以获取字符串和子字符串作为输入,并返回一个包含子字符串所有出现位置索引的列表。这将使我们能够快速有效地检索所有匹配项,而不必逐个搜索。

解决方案:循环查找

解决此问题的一种简单方法是循环遍历字符串,并使用 find() 方法逐个查找子字符串。每当找到一个匹配项时,我们就将索引添加到结果列表中。然后,我们更新搜索的开始索引,以继续查找后续匹配项。以下代码展示了这种方法:

def find_all(string, sub):
  """返回字符串中所有子字符串出现位置的索引列表。

  Args:
    string: 输入字符串。
    sub: 要查找的子字符串。

  Returns:
    包含所有出现位置索引的列表。
  """
  result = []
  start = 0
  while True:
    index = string.find(sub, start)
    if index == -1:
      break
    result.append(index)
    start = index + 1
  return result

优化:KMP 算法

虽然循环查找方法可以正常工作,但对于较长的字符串和子字符串,它可能会变得低效。为了提高性能,我们可以采用 Knuth-Morris-Pratt (KMP) 算法。KMP 算法使用预处理表来加速模式匹配过程,从而显着减少所需的比较次数。

使用外部库

除了自己实现 KMP 算法之外,我们还可以利用 Python 中可用的外部库,例如 re 模块。re 模块提供了 findall() 方法,该方法返回所有匹配项的列表,非常适合查找所有子字符串出现的位置。以下代码展示了如何使用 findall()

import re

def find_all(string, sub):
  """返回字符串中所有子字符串出现位置的索引列表。

  Args:
    string: 输入字符串。
    sub: 要查找的子字符串。

  Returns:
    包含所有出现位置索引的列表。
  """
  matches = re.findall(sub, string)
  return [match.start() for match in matches]

结论

查找字符串中所有子字符串出现的位置在各种字符串处理应用程序中都至关重要。本文讨论了 Python 中使用循环查找、KMP 算法和外部库的三种方法。通过选择最适合特定需求的方法,我们可以高效准确地检索所有匹配项。

常见问题解答

  1. 循环查找和 KMP 算法之间的区别是什么?
    循环查找逐个字符比较字符串,而 KMP 算法使用预处理表来加速模式匹配过程。

  2. 哪种方法更有效率?
    对于较长的字符串和子字符串,KMP 算法通常更有效率。

  3. findall() 方法有什么优势?
    findall() 方法不需要自己实现模式匹配算法,并且可以轻松地与正则表达式一起使用。

  4. 我应该在什么时候使用这些方法?
    当需要查找所有匹配项而不是单个匹配项时,可以使用这些方法。

  5. 这些方法有什么局限性?
    这些方法无法处理重叠匹配项,例如在模式匹配中出现的子字符串。