HOWTO · Python

在 Python 字符串中查找字符的所有索引

我们可以使用正则表达式、yield 关键字和列表推导式在 Python 中查找字符串中某个字符的所有索引。

本页内容

要查找 Python 字符串中某个字符的所有出现位置,可以将 enumerate() 与条件判断结合起来,收集所有匹配的索引。Python 的索引从 0 开始,因此第一个字符的索引是 0。下面的示例使用字符串 "This is a string",查找小写字母 "i"。

使用 enumerate() 和列表推导式查找字符的所有索引

对于给定的字符串和目标字符,这个列表推导式会按顺序返回所有匹配的索引。运行此示例:

本节中的代码以及显示的标签或输出仍为英文。

string = "This is a string"
char = "i"
indices = [index for index, character in enumerate(string) if character == char]
print(indices)

enumerate(string) 会为每个字符提供一组值:它的索引和值。条件判断只会在该值等于 char 时保留对应索引,列表推导式则会将这些索引收集到一个新列表中。对于示例输入,匹配位置是 2、5 和 13。匹配区分大小写:搜索 "I" 不会匹配小写的 "i"。如果目标字符没有出现,结果就是 []。当调用方需要一次取得所有索引时,这种方式通常最清晰。

使用 yield 惰性生成匹配的索引

如果需要逐个处理结果,或输入数据较大,生成器会很有用。下面的函数采用与列表推导式相同的比较方式和顺序,但会在迭代过程中逐个产出索引。

本节中的代码以及显示的标签或输出仍为英文。

def find_indexes(string, char):
    for index, character in enumerate(string):
        if character == char:
            yield index


string = "This is a string"
char = "i"
indices = list(find_indexes(string, char))
print(indices)

调用 find_indexes(string, char) 会创建一个生成器;只有在请求值时,函数体才会运行。可以使用 for 循环逐个处理索引;如果需要完整列表,则可以将调用包装在 list(...) 中。将生成器转换为列表后,得到的索引与列表推导式相同。如果没有匹配项,迭代不会产生任何值,而 list(...) 的结果是 []。yield 关键字会在向调用方提供一个值时暂停函数,随后在下一次迭代时继续执行。

使用正则表达式查找字符的所有索引

本文中的三种方法都要求 char 是只包含一个字符的 Python 字符串。这个共同的输入前提让逐字符比较和正则表达式示例保持一致。当搜索条件适合用正则表达式模式描述时,可以使用 re.finditer()。每个匹配对象都可以通过 start() 提供其起始位置。如果目标是作为数据传入的字面字符,应先将它传给 re.escape();否则,.、* 或 [ 等字符可能会被解释为正则表达式语法,而不是按字面值进行搜索。

本节中的代码以及显示的标签或输出仍为英文。

import re

string = "This is a string"
char = "i"
pattern = re.escape(char)
indices = [match.start() for match in re.finditer(pattern, string)]
print(indices)
[2, 5, 13]

当目标是字面字符时,转义很重要,尤其是目标可能包含正则表达式元字符时。如果确实要搜索一个模式,就将该模式直接传给 re.finditer(),不要对它进行转义。对于单个字面字符,enumerate() 更简单;只有当匹配规则需要使用模式特性时,正则表达式才更有用。三种方法都会从左向右扫描,保留重复匹配,并返回从 0 开始的位置。