【Python】文字列に特定の文字やパターンを含むか確認する方法をわかりやすく解説
はじめに
Pythonで文字列に特定の文字列が含まれているかどうかを判定したい場面は多いかもしれません。
たとえば、ユーザーが入力したテキストの中から特定のキーワードを探したい場合や、ファイル内の情報を整理したい場合など、実務でもよく出てくる作業だと思います。
そこで、Pythonの文字列操作について、初心者の方でもわかりやすいように丁寧に説明します。
文字列が含まれているかどうかを確認する方法として、in
演算子や文字列メソッドの find()
、さらには正規表現を扱う re
モジュールなど、さまざまなアプローチがあります。
この記事では、それぞれの使い方を例を交えて解説するとともに、それをどのようなシーンで活かせるか、実務に直結するイメージもできるようにまとめます。
この記事を読むとわかること
- Pythonで文字列を判定するための代表的な方法
in
やfind()
メソッドを使ったシンプルな検索- 正規表現を使ったパターンマッチングの基礎
- 大文字・小文字を区別する場合の対処法
- ログ解析などの実務的な活用イメージ
Pythonで文字列を扱う基本
Pythonでは、文字列は単なるテキストデータというだけでなく、多彩なメソッドをもつ便利なオブジェクトでもあります。
文字列オブジェクトは str
型として扱われ、"Hello"
のようにダブルクォートやシングルクォートで囲むことで定義します。
たとえば以下のような形で文字列を変数に代入します。
text = "Hello, world!"
これで変数 text
には「Hello, world!」という文字列が格納されました。
次に、Pythonの文字列にはどのような特長があるかを簡単に見ておきましょう。
たとえばイミュータブル(変更不可)であることが挙げられます。
つまり、文字列の一部だけを書き換えるといった操作はできません。
そのため、何か加工や変換を行う際には新しい文字列を生成するのが一般的です。
また、Pythonの文字列では添字(インデックス)で特定の文字を取得することができます。
text[0]
と書けば、一番最初の文字「H」を取得できます。
ただし、文字の取り出しは可能でも書き換えはできない点には注意が必要です。
部分文字列の判定方法
部分文字列とは、ある文字列の中に含まれる連続した文字のかたまりのことです。
たとえば Python
という文字列の中に th
という文字列が含まれていれば、それが部分文字列です。
この判定にはいくつかの方法があります。
ここでは、初心者の方でも扱いやすい in
演算子、そして文字列メソッドの find()
や index()
を中心に見ていきます。
シンプルな例として「指定したワードが文章の中に含まれていればメッセージを表示する」というコードを考えてみましょう。
具体的には、ユーザーのコメントを監視して、禁止用語が含まれているかどうかをチェックするといったシーンでよく使われます。
このようなチェックはウェブアプリケーションやチャットボットでも頻出するでしょう。
一般的に、部分文字列が含まれているかどうかを素早く判定するなら in
演算子や find()
で十分なケースが多いです。
ただし、パターンが複雑になる場合は正規表現が必要かもしれません。
まずはシンプルな部分文字列の確認から始めましょう。
in演算子による簡単な判定
Pythonで文字列の中に特定の文字列が含まれているかどうかを判定する最もシンプルな方法は、in
演算子です。
"Apple" in "Apple Pie"
のように記述すると、含まれていれば True
、含まれていなければ False
が返ります。
以下の例を見てください。
text = "Pythonで文字列を検索する方法を学ぶ" keyword = "検索" if keyword in text: print("検索というワードが含まれています。") else: print("検索というワードは含まれていません。")
この例では、変数 text
に格納された文章の中に keyword
が存在するかどうかを調べています。
if keyword in text:
の行が、部分文字列を判定するためのシンプルな記述です。
実際の開発現場でも、まずはこの書き方で文字列が含まれているかを素早くチェックできることを覚えておくと便利です。
in
演算子は可読性が高く、パフォーマンスの面でも多くのケースで十分使えます。
たとえば数十MB程度のテキストファイルであれば、in
を利用して単純検索を行っても体感的には十分に早いことが多いでしょう。
ただし、テキストが極端に大きい場合や、より複雑なパターンを必要とする場合には、別の手法を検討する必要があります。
find()メソッドの活用
in
演算子に加えて、Python文字列のメソッドである find()
もよく使われます。
find()
は、指定した文字列が見つかった場合に、その開始位置のインデックス(0から始まる位置)を返し、見つからなかった場合には -1
を返します。
インデックスを知りたいときには in
演算子よりも便利です。
以下は find()
の使用例です。
text = "東京都千代田区永田町にオフィスがあります" location = text.find("永田町") if location != -1: print("永田町は", location, "番目の位置にあります。") else: print("文字列内に見つかりませんでした。")
ここで location
が -1
でなければ、指定したワードが何番目にあるかを出力できます。
このように、文字列が含まれているかどうかだけでなく、その文字列がどこにあるかを知りたいときは find()
が役立ちます。
また、類似のメソッドとして index()
も存在します。
index()
は find()
と同様に開始インデックスを返す点は同じですが、指定した文字列が見つからない場合にエラー(ValueError)を発生させるという違いがあります。
エラーをキャッチして処理したいケースでは index()
を使うこともあるでしょう。
count()やstartswith()などの応用
部分文字列を含むかどうかを調べる関連のメソッドとして、count()
や startswith()
, endswith()
なども覚えておくと便利です。
これらは検索そのものに加えて、文字列の先頭や末尾の判定、特定のキーワードが何回登場するかの把握など、さまざまなシーンで活躍します。
たとえば count()
は、指定した文字列が文章の中に何回現れるかを数えてくれます。
これは文章の中に含まれるキーワードの頻度を調べたい場合に有用です。
次の例では簡単に回数を確認しています。
text = "Pythonは簡単に書ける。Pythonはとても柔軟だ。" count_python = text.count("Python") print("Pythonという単語は", count_python, "回含まれています。")
startswith()
と endswith()
は、それぞれ文字列が特定の文字列で始まっているか、終わっているかを判定するメソッドです。
ファイル名の拡張子チェックなどにも利用できます。
たとえば .csv
ファイルだけを処理したいときは、endswith(".csv")
でチェックするだけなので簡単です。
reモジュールでのパターンマッチング
in
演算子や find()
が文字列の単純な検索を行うための方法だとすると、re
モジュールは複雑なパターンマッチングを行いたいときに頼りになります。
re
モジュールを使うと正規表現で部分文字列を検索したり、置換や分割などをまとめて行うことが可能です。
たとえば「アルファベットと数字が混在した特定の形式の文字列だけ取り出す」といった要望を実装できます。
Pythonで正規表現を使うためには、まず import re
と書いてモジュールをインポートします。
たとえば、以下のようなコードを見てみましょう。
import re text = "ユーザーID: user123, 取引ID: trade456, その他: data789" pattern = r"user\d+" # 「user」という文字列のあとに数字が続くパターン match = re.search(pattern, text) if match: print("見つかった文字列:", match.group()) else: print("パターンに一致する文字列は見つかりませんでした。")
re.search()
は、テキスト全体の中で指定した正規表現パターンにマッチする最初の箇所を返してくれます。
ここでは r"user\d+"
というパターンを使って、「user」のあとに数字が1回以上続く部分文字列を探しています。
もし一致する部分があれば match
オブジェクトを取得でき、match.group()
でその部分文字列を取り出せます。
正規表現を使うときは、パターンの文法をしっかり把握しておく必要があります。
複数の数字や文字が混ざり合うような複雑な検証をしたいときや、柔軟に文字列をフィルタリングしたいときには非常に便利な方法といえるでしょう。
正規表現パターンの基本
正規表現は、文字の並びを表現するための特殊な構文を提供します。
代表的なものは次のとおりです。
.
は任意の1文字を表す\d
は数字を表す([0-9]
と同じ)\w
は英数字とアンダースコアを表す([A-Za-z0-9_]
)+
は直前のパターンが1回以上繰り返されることを示す*
は直前のパターンが0回以上繰り返されることを示す^
は行頭を表す$
は行末を表す
これらを組み合わせることで、例えば「英数字が5〜10文字続く場合のみマッチ」や「先頭に特定の文字が含まれている場合」など、より細かい条件を設定できます。
Pythonで実装するときは、re.match()
で先頭からマッチをチェックしたり、re.fullmatch()
で文字列全体を正規表現に当てはめたりといった使い分けが必要です。
なお、部分文字列の検索には re.search()
、すべてのマッチ箇所を取得するには re.findall()
などもあります。
こうした多彩なメソッドを使いこなすことで、単純な部分文字列検索だけでなく、メールアドレスや特定のフォーマットをもつ文字列をフィルタリングするといった応用的な処理ができるようになるでしょう。
正規表現での部分文字列の検索
正規表現を使った部分文字列の検索は、パターンに柔軟性が欲しいケースで便利です。
例えば、ハイフン付きの電話番号を検索したい場合や、特定の接頭辞をもつIDをすべて取り出したい場合などが考えられます。
以下の例は、電話番号の一例として「XXX-XXXX-XXXX」のような書式をもつ部分文字列を探す場合です。
import re text = "顧客A: 090-1234-5678, 顧客B: 080-8765-4321, 顧客C: 03-9999-8888" pattern = r"\d{2,4}-\d{3,4}-\d{3,4}" found = re.findall(pattern, text) if found: print("見つかった電話番号:", found) else: print("電話番号は見つかりませんでした。")
この例では \d{2,4}
のように書いて、数字が2〜4桁続くという部分を表現しています。
その後ろにハイフンが入り、再び数字が3〜4桁続く、といったルールを記述することで、形式に合った番号だけを検索できます。
もちろんこれは一例なので、実際の電話番号パターンはもっと多様ですが、正規表現を使えばある程度柔軟な抽出ができることがわかるでしょう。
なお、電話番号のようにフォーマットが厳密に決まっているわけではないデータの場合は、この正規表現だけで完全に洗い出せるとは限りません。
それでも、簡易的なフィルタリングや一括抽出を行うには非常に有力なアプローチです。
大文字・小文字の区別と変換
文字列を検索する際、大文字と小文字を区別するかどうかも重要です。
ユーザーが入力した文字列の中に「Apple」という語が含まれているかを検索したい場合、"apple"
や "APPLE"
をどこまで同一視するのかは要件次第でしょう。
Pythonでは in
演算子も find()
も、デフォルトでは大文字と小文字を区別して検索します。
大文字・小文字を区別せずに検索したい場合、文字列をあらかじめ小文字(あるいは大文字)に統一しておくとシンプルです。
たとえば以下の例のようにします。
text = "Python" keyword = "python" if keyword.lower() in text.lower(): print("区別せずに検索した場合、含まれています。")
上記のように .lower()
メソッドでどちらも小文字化すれば、実質的に大小区別なしで判定できます。
これは正規表現でも同様で、re
モジュールでは re.IGNORECASE
というフラグを指定すると大小無視の検索が可能です。
import re text = "PyThOn" pattern = "python" match = re.search(pattern, text, re.IGNORECASE) if match: print("大文字小文字を区別せずに検索してヒットしました。")
こうした機能を活用することで、ユーザー入力のゆれを吸収して正しく検索できるようになります。
フォーム入力やチャットメッセージなど、文字の大小が混ざりやすい環境では重宝します。
実務での活用シーン1: ログ解析
プログラミングの実務では、ログファイルを解析して特定の文字列を探す作業が頻繁に発生します。
例えばウェブサーバーのアクセスログから特定のURLパターンだけをピックアップしたり、エラーログの出力内容を集計したりするケースです。
Pythonを使えば、in
や find()
を組み合わせたシンプルな検索であっても、テキストファイルを1行ずつ読み込みながら特定のキーワードを含む行だけを抽出するといった処理を短いコードで実装できます。
もし、抽出条件が複数あったり複雑なパターンが必要であれば、正規表現を活用することで汎用的かつパワフルなソリューションに発展させられます。
例えば、下記のようにログファイルを読み込み、エラーコード ERROR
を含む行だけを取り出すスクリプトを書けます。
error_lines = [] with open("server.log", "r", encoding="utf-8") as f: for line in f: if "ERROR" in line: error_lines.append(line.strip()) print("エラー行の抽出結果:") for err in error_lines: print(err)
このように、指定した文字列を含むかどうかでフィルタリングするだけでも多くの場面で役立つでしょう。
本格的にログを解析し、時系列でのパターンや複数のキーワードの同時出現などを調べたければ正規表現や集計ロジックを組み合わせることになります。
それでも、まずは「含まれるかどうか」のチェックが最初の一歩になるケースは多いです。
実務での活用シーン2: メール本文の検索
もうひとつの実務的な例として、メール本文の検索があります。
メールの内容に特定のキーワードが含まれているか判定し、それに応じて振り分けを行うシステムはよく使われます。
たとえば「クレーム」「問い合わせ」「要望」というキーワードが含まれるメールだけを抽出して対応したい、といったケースを想像してみましょう。
この場合でも、in
演算子を使うとシンプルに実装できます。
複数のキーワードがあるなら、ループやリストを使って一括チェックすることも可能です。
keywords = ["クレーム", "問い合わせ", "要望"] mail_body = "本日のお問い合わせは新サービスに関するもので..." for word in keywords: if word in mail_body: print(f"'{word}'が含まれているので、フォルダへ振り分けます。") # ここでフォルダ振り分け処理などを書く
さらに、メール本文に含まれる特定の情報を抽出して別の形で保存したい場合には、正規表現を使って細かい部分を切り出すことも考えられます。
「日時情報だけ取り出す」「金額情報をすべてピックアップする」など、多岐にわたる操作が行えます。
実務ではメール本文や添付ファイルを扱うときに、文字コードやファイル形式によって少し処理が複雑になることがあります。
しかし文字列検索の基本となる考え方は同じで、in
や find()
, re
モジュールを状況に応じて使い分けることがポイントです。
エラーを回避するコツ
文字列検索をしているときに起こりうるエラーとして、index()
を使う場合に対象文字列が見つからないと ValueError が出ることがあります。
そういう場面では、find()
と組み合わせてエラーを回避したり、try
〜 except
構文で処理を囲んだりといった対策が必要です。
また、正規表現を使う際に、思わぬ部分にもマッチしてしまったり、大量のテキストを処理することでパフォーマンスが低下する場合もあるので注意が必要です。
正規表現パターンが複雑すぎると、計算量が増えて処理が重くなるケースがあります。
ここでは、コードの最適化やパターンの見直しが効果的です。
テキストの文字コードが想定と異なっている場合もエラーや文字化けの原因になります。
ファイルを開くときには encoding="utf-8"
のようにエンコーディングを明示する、あるいは外部から受け取るデータの形式をよく確認しておくことが重要です。
文字列検索でトラブルを回避するには、まずは想定されるデータ形式や大きさを把握しておくことが大事です。
想定外の文字コードや巨大ファイルに対しても落ちない仕組みを組んでおくことで、後からの不具合を減らすことにつながります。
文字列検索の方法まとめ表
ここで、これまでに紹介してきた代表的な文字列検索方法を簡単な表にまとめてみましょう。
方法 | 使い方 | 見つからない場合 | メリット |
---|---|---|---|
in 演算子 | sub in text | False を返す | シンプルで読みやすい |
find() | text.find(sub) | -1 を返す | インデックスが取得できる |
index() | text.index(sub) | 例外(ValueError)が発生 | 例外処理で分岐しやすい |
count() | text.count(sub) | 0 を返す | 登場回数をすぐに把握できる |
startswith() / endswith() | text.startswith(prefix) etc. | False を返す | 文字列の先頭/末尾を判定可能 |
正規表現 (re.search() ) | re.search(pattern, text) | None を返す | 複雑なパターンを柔軟に扱える |
このように、用途によって使い分けるメソッドや演算子が異なります。
単純に含まれるかだけ判定したいなら in
で済みますし、複雑なパターンなら正規表現が必要になるでしょう。
具体的なケーススタディ1: ユーザー名のバリデーション
たとえば、ウェブサービスでユーザー登録を行うとき、ユーザー名に使っていい文字や文字数を制限することがあります。
このとき、指定外の文字が含まれていないかをチェックするのにも文字列検索や正規表現が役立ちます。
「アルファベットと数字、アンダースコアだけが許可される」というルールを実装する際の例を見てみましょう。
import re def is_valid_username(username): # ^と$で文字列の先頭と末尾を指定し、その間が許可文字のみかをチェック pattern = r"^[A-Za-z0-9_]+$" match = re.fullmatch(pattern, username) return match is not None test_names = ["valid_user", "user@domain", "User123", "userName!"] for name in test_names: if is_valid_username(name): print(name, "は有効なユーザー名です。") else: print(name, "は無効なユーザー名です。")
ここでは re.fullmatch()
を使い、ユーザー名全体が [A-Za-z0-9_]
のいずれかの文字のみで構成されているかを確認しています。
ユーザー名に特定の文字列が「含まれてはならない」場合も同様で、ルール違反の文字列を in
演算子でチェックしてNGを出す方法なども考えられます。
具体的なケーススタディ2: CSVファイルのカラム抽出
CSVファイルのあるカラムに特定のキーワードが含まれている行だけを抜き出したい場合もあります。
これはデータ分析や顧客リストの絞り込みなど、実務で多用するパターンです。
以下の例のように、split()
を使って行をカラム単位に分割しつつ、特定のカラムに検索キーワードが含まれるかチェックできます。
keyword = "VIP" filtered_rows = [] with open("customers.csv", "r", encoding="utf-8") as f: for line in f: columns = line.strip().split(",") # 例: カラム0が顧客名、カラム1が顧客ステータスなど if len(columns) > 1: status = columns[1] if keyword in status: filtered_rows.append(line.strip()) print("該当行:") for row in filtered_rows: print(row)
この例では、カラム1(顧客ステータスなど)に VIP
というキーワードが含まれる行を抽出しているイメージです。
こうした処理をもう少し高度にしたい場合、正規表現を使ってパターンでマッチングするとより柔軟です。
実務では、カラム数や行数が膨大になる場合もあるので、必要に応じて処理を最適化するか、Pythonのライブラリ(ただし、外部ライブラリに依存しすぎない範囲で)を検討することも選択肢になります。
具体的なケーススタディ3: Webスクレイピングでの情報抽出
Webスクレイピングによって取得したHTMLの中から、特定の情報を抜き出すことも文字列検索の大きな応用例です。
シンプルなスクレイピングなら、HTMLソースコードをまるごと文字列として取得して、in
や find()
で必要な部分を探すことができます。
しかし、要素のクラス名やタグ構造を正確に解析するには、HTMLパーサーや正規表現を活用する場合が多いです。
例えば、取得したHTMLに <span class="price">
というタグがあったとして、その部分を抽出したいときは、正規表現で class="price"
にマッチする箇所を探し、次のタグ終了までを取り出すなどの処理が考えられます。
ただし、HTMLは構造が複雑なため、正規表現だけで完璧に解析するのは難しいケースもあります。
Beautiful Soup のようなHTMLパーサーを併用すれば、要素選択が楽になるでしょう(ただし外部ライブラリの紹介はここでは避けます)。
それでも「とりあえず文字列として検索し、ざっくりどのへんに必要情報があるかを見つける」という初歩的な工程は、どんな方法でも共通して大事です。
検索キーワードにマッチするところを足がかりにして、さらに詳細な解析を加える、という段階的なアプローチが現実的でしょう。
さらに複雑なパターンへの対処法
実務では、単なる文字列の検索だけでなく、抽出したいデータが多層構造になっていたり、複数の条件が絡む場合もあります。
その際には以下のような工夫が考えられます。
- 複数キーワードを同時に扱う: すべてのキーワードを含む行だけを残す、逆にいずれか1つでも含めば残すなど、条件を工夫する。
- 順序関係の考慮: 文字列Aの後に文字列Bが来る場合だけを検索するなど。正規表現の先読みや後読みが役立つこともある。
- 条件分岐を組み合わせる: if 文のネストを深くして条件を細分化し、
in
やfind()
といった基本メソッドを使いつつ処理する。
ただし、あまりに複雑な検索をひとつの正規表現や条件式で処理すると、保守性が下がる恐れがあります。
コードを見ただけで何を検索しようとしているか分かりにくくなることもあります。
そこで、適度にコードを分割し、検索条件をわかりやすい塊に整理する設計が必要です。
あまりにも大きな正規表現パターンを1行に詰め込むと、後から読み返したときに何をしたいのか分からなくなることがあります。
必要に応じて複数のステップに分けたり、変数名を工夫したりして可読性を保ちましょう。
まとめ
Pythonで文字列に特定のキーワードが含まれているかどうかを調べる方法は、初心者の方でも意外と簡単に扱えることがおわかりいただけたのではないでしょうか。
in
演算子が最も基本的で読みやすい書き方ですが、find()
や index()
、count()
などもそれぞれにメリットがあります。
そして、複雑なパターンマッチが必要な場合には正規表現を使えばより柔軟な実装が可能です。
実務においては、ログ解析、メール本文の自動仕分け、ユーザー名のバリデーション、CSVファイルのキーワード抽出、Webスクレイピングなど、幅広いシーンで文字列検索が活躍します。
実際に試してみると、ほんの数行のコードで有用な結果を得られる場合が多いでしょう。
皆さんもまずは in
や find()
から始めて、必要に応じて re
モジュールを使ったパターンマッチングを取り入れてみてください。
文字列検索はどのプログラミング言語でも重要な基本ですが、Pythonではシンプルな文法と豊富なメソッドのおかげで、スムーズに習得できるはずです。
ぜひ一歩ずつ取り組んでみてください。