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 で一致するインデックスを遅延生成する
結果を1つずつ処理したい場合や、入力が大きい場合はジェネレーターが便利です。次の関数はリスト内包表記と同じ比較方法と順序を使い、反復処理が進むたびに各インデックスを返します。
このセクションのコードと表示されるラベルや出力は英語のままです。
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 キーワードは呼び出し元に値を渡す間、関数を一時停止し、次の反復で処理を再開します。
正規表現で文字のインデックスをすべて取得する
この記事の3つの方法では、char は1文字の 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() に直接渡してください。リテラルの1文字を検索するだけなら enumerate() のほうが簡潔です。照合ルール自体にパターン機能が必要な場合に、正規表現が役立ちます。3つの方法はいずれも左から右へ調べ、繰り返し現れる文字も保持し、0 から始まる位置を返します。