閉じる

Pythonのfind()とindex()で文字列を検索する方法

文字列の中から特定の単語や記号を探す処理は、ログ解析や入力チェック、テキスト整形などで頻繁に登場します。

本記事ではPythonのfind()index()を中心に、違い、startend引数の使い方、右から検索するrfindrindex、そして実務での使い分けまでを丁寧に解説します。

Pythonの文字列検索 find()とindex()の基本

役割と戻り値の違い

find()index()はいずれも部分文字列を探して先頭の位置を返しますが、見つからなかった場合の挙動が異なります。

find()は-1を返し、index()ValueErrorを送出します。

右から探すペアとしてrfind()rindex()もあります。

以下に主な違いをまとめます。

メソッド見つかった場合見つからない場合検索方向用途の目安
find(sub[, start[, end]])最初の一致位置の整数-1左→右失敗を許容して進めたい場合
index(sub[, start[, end]])最初の一致位置の整数ValueError左→右見つからないのを例外として扱いたい場合
rfind(sub[, start[, end]])最後の一致位置の整数-1右→左(位置は左起点)最後の一致が必要だが失敗は許容
rindex(sub[, start[, end]])最後の一致位置の整数ValueError右→左(位置は左起点)最後の一致が必須で失敗は例外

in演算子で存在有無だけを調べることもできますが、本記事では位置が必要な場面を中心に扱います。

シンタックスと引数(start, end)

それぞれのシグネチャは以下の通りです。

  • s.find(sub[, start[, end]])
  • s.index(sub[, start[, end]])

startは検索を始める位置のインデックス、endは検索を終える位置のインデックスです。

どちらもスライスと同じくstartは含む、endは含みません。

また、負の値も指定でき、右からのオフセットとして解釈されます。

Python
# 文字列中のインデックスとstart/endの挙動を確認する例
s = "abracadabra"
#        01234567890  ← インデックス

print(s.find("abra"))          # 先頭から最初の一致
print(s.find("abra", 1))       # 位置1以降で検索
print(s.find("a", 3, 9))       # [3, 9) の範囲で検索
print(s.find("bra", -5))       # 右から5文字目以降で検索
実行結果
0
7
3
8

上の例では、endは含まれないため[start, end)の半開区間になる点が重要です。

右から検索するrfindとrindex

末尾側に近い一致を取りたいときはrfind()rindex()を使います。

返される位置は左端からのインデックスであり、見つからない場合の挙動はfind()index()に準じます。

Python
s = "one two two three two"
print(s.rfind("two"))   # 最後の"two"の開始位置
print(s.rindex("two"))  # 同上。見つからない場合はValueError
実行結果
18
18

find()の使い方

一致位置を取得する基本

最初の一致の開始インデックスを整数で受け取れます。

Python
# 基本的なfindの使用例
text = "Python makes coding fun"
pos = text.find("coding")
print(f"coding の開始位置は {pos} です")
実行結果
coding の開始位置は 13 です

見つからない時は-1を返す

find()は見つからない場合に-1を返します。

存在有無を判定するだけならin演算子が簡潔ですが、位置が必要な場合は-1との比較を必ず行います。

Python
# 見つからない場合は-1
text = "Python makes coding fun"
pos = text.find("Java")

if pos == -1:
    print("Java は見つかりませんでした")
else:
    print(f"Java は位置 {pos} にあります")
実行結果
Java は見つかりませんでした

位置を使って部分文字列を取り出す

find()で得た位置とスライスを組み合わせると、可変長の部分文字列を安全に取り出せます。

Python
# URLからドメインを取り出す例
url = "https://example.com/path/index.html"

scheme_sep = "://"
sep_pos = url.find(scheme_sep)
if sep_pos == -1:
    raise ValueError("URLにスキーム区切り(://)がありません")

start = sep_pos + len(scheme_sep)  # ドメインの開始位置
end = url.find("/", start)         # ドメインの終了位置(最初のスラッシュ)
if end == -1:
    end = len(url)                 # スラッシュが無ければ末尾まで

domain = url[start:end]
print(domain)
実行結果
example.com

このように、startlen(見つけた区切り)だけ進め、次の区切りの位置をfind()で求めるのが定石です。

index()の使い方

一致位置を取得する基本

index()find()と同じ位置を返しますが、見つからないときに例外を送出します。

必ず存在する前提のデータを扱うときに向いています。

Python
# 基本的なindexの使用例
text = "Python makes coding fun"
pos = text.index("coding")
print(f"coding の開始位置は {pos} です")
実行結果
coding の開始位置は 13 です

見つからない時はValueError

見つからない場合はValueError: substring not foundとなります。

未処理のままにするとプログラムはそこで停止します。

Python
# 見つからない場合のindexは例外を送出
text = "Python makes coding fun"
print(text.index("Java"))  # ここで例外
実行結果
Traceback (most recent call last):
  File "sample.py", line 3, in <module>
    print(text.index("Java"))  # ここで例外
          ~~~~~~~~~~^^^^^^^^
ValueError: substring not found

try-exceptでのエラー処理

index()の失敗を業務的なエラーメッセージに置き換えたい場合は、try-exceptValueErrorを捕捉します。

Python
# 設定行 key=value の形式を検証する例
def parse_kv(line: str) -> tuple[str, str]:
    try:
        eq = line.index("=")  # 必須
    except ValueError:
        # 形式エラーとして説明的な例外を投げ直す
        raise ValueError(f"不正な形式です: {line!r}. 'key=value' 形式にしてください")
    key = line[:eq].strip()
    value = line[eq + 1 :].strip()
    return key, value

print(parse_kv("timeout = 30"))
try:
    print(parse_kv("invalid line"))
except ValueError as e:
    print(f"エラー: {e}")
実行結果
('timeout', '30')
エラー: 不正な形式です: 'invalid line'. 'key=value' 形式にしてください

index()は存在必須の前提や、異常系を例外としてハンドリングしたい場合に適しています。

find()とindex()の使い分け

失敗を許容するならfind

オプショナルな文字列や、見つからなくても処理を継続したい場合はfind()が適しています。

-1を基準に分岐し、見つかったときだけ処理します。

Python
# "NOTE:" があれば抽出し、なければ何もしない
line = "ID=42; USER=alice; NOTE: urgent"
pos = line.find("NOTE:")
if pos != -1:
    note = line[pos + len("NOTE:") :].strip()
    print(f"注記: {note}")
else:
    print("注記はありません")
実行結果
注記: urgent

厳密なエラー制御ならindex

存在しなければ不正データとみなす場合は、index()で例外を使って確実に検知します。

Python
# ログレコードに必須の区切り "--" が無ければ例外
record = "2025-08-31 12:34:56 -- OK"
try:
    sep = record.index("--")
    left = record[:sep].strip()
    right = record[sep + 2 :].strip()
    print(left, right)
except ValueError:
    # 監視対象などでは例外のまま上位に伝播させるのも有効です
    raise RuntimeError("レコード形式が不正です")
実行結果
2025-08-31 12:34:56 OK

部分範囲検索で効率化する

巨大な文字列や繰り返し検索では、startendを使って探索範囲を絞ると無駄な走査を減らせます。

複数一致を左から順に列挙する場合もstartを更新していくのが定石です。

Python
# 複数一致の位置を列挙する。毎回 start を進めて部分範囲検索
text = "bananarama"
sub = "ana"
start = 0
positions = []

while True:
    pos = text.find(sub, start)
    if pos == -1:
        break
    positions.append(pos)
    start = pos + 1  # 重なりを許すなら +1、許さないなら +len(sub)

print(positions)  # [1, 3]
実行結果
[1, 3]

endも併用すれば、例えば特定のセクション内だけを検索する、といった効率化も可能です。

-1の扱いミスを防ぐ

find()の戻り値をそのまま真偽値として使うのはバグの温床です。

Pythonでは-1は真と評価されるため、見つからないのに条件が真になってしまいます。

Python
# 悪い例: 見つからない(-1)のに真と判定される
s = "abc"
if s.find("z"):             # -1 は True として扱われる
    print("found?")         # 実際は見つかっていないのに出力される
else:
    print("not found")

# 良い例1: -1と比較する
if s.find("z") != -1:
    print("found")
else:
    print("not found")

# 良い例2: 存在有無だけなら in 演算子を使う
print("z" in s)             # False
実行結果
found?
not found
False

存在チェックだけならin演算子、位置が必要ならfind()-1比較、存在必須ならindex()try-exceptという方針でミスを減らせます。

まとめ

find()index()はどちらも一致位置を返しますが、見つからない場合の挙動が異なります。

失敗を許容したいならfind()で-1を扱い、存在必須ならindex()で例外処理を行うのが安全です。

startendで検索範囲を絞ると無駄な走査を減らせ、rfind()rindex()で末尾に近い一致を簡単に得られます。

また、find()の戻り値をそのまま真偽値に使うと-1が真になる落とし穴があるため、!= -1で比較するかin演算子を用いると良いです。

ここで解説した基本と注意点を押さえておけば、ログ解析や文字列パースなどの現場で堅牢かつ効率的なコードが書けます。

この記事を書いた人
エーテリア編集部
エーテリア編集部

人気のPythonを初めて学ぶ方向けに、文法の基本から小さな自動化まで、実際に手を動かして理解できる記事を書いています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!