C++で文字列を検索する場合、基本的には std::string の検索機能を使います。
特に代表的なのが find() です。
find() を使うと、文字列の中に特定の文字や文字列が含まれているかを調べられます。
見つかった場合は、その文字列が始まる位置を返し、見つからなかった場合は std::string::npos という特別な値を返します。
C++で文字列検索を学ぶときは、まずこの find() と std::string::npos の考え方を理解することが大切です。
C++の文字列検索でよく使う関数
C++には、文字列を検索するための関数がいくつか用意されています。
find()
find() は、文字列を前から検索するための関数です。
指定した文字や文字列が含まれているかを調べるときに最もよく使われます。
検索対象が見つかった場合は、その開始位置を返します。
見つからなかった場合は std::string::npos を返します。
たとえば、文章の中に特定の単語が含まれているかを調べたい場合や、メールアドレスの中に @ が含まれているかを確認したい場合などに使えます。
rfind()
rfind() は、文字列を後ろから検索するための関数です。
最後に出てくる文字や文字列の位置を知りたいときに便利です。
たとえば、ファイル名から拡張子を取り出したい場合に、最後のドットの位置を探す用途などで使われます。
find_first_of()
find_first_of() は、指定した複数の文字のうち、どれか1つが最初に出てくる位置を検索する関数です。
たとえば、カンマやピリオド、感嘆符など、複数の記号のうち最初に出てくるものを探したい場合に使えます。
find_first_not_of()
find_first_not_of() は、指定した文字に含まれない文字を前から検索する関数です。
たとえば、文字列の先頭にある空白を飛ばして、最初の空白以外の文字を探したい場合に便利です。
文字列の前後の空白を削除する処理でもよく使われます。
find_last_of()
find_last_of() は、指定した複数の文字のうち、どれか1つが最後に出てくる位置を検索する関数です。
ファイルパスの中から最後の区切り文字を探し、ファイル名だけを取り出したい場合などに使われます。
find_last_not_of()
find_last_not_of() は、指定した文字に含まれない文字を後ろから検索する関数です。
文字列の末尾にある空白や改行を取り除きたい場合などに役立ちます。
find()を使った文字列検索の基本
C++で文字列を検索する場合、まず覚えておきたいのが find() です。
find() は、検索したい文字や文字列が対象の文字列に含まれているかを調べます。
見つかった場合は、その位置を返します。
C++の文字列の位置は、1番目ではなく0番目から数えます。
たとえば、文字列の先頭にある文字の位置は 0 です。2文字目は 1、3文字目は 2 というように数えます。
そのため、検索結果として返ってくる数値は、人間が普段数える「1文字目、2文字目」とは少しずれる点に注意が必要です。
std::string::nposとは
std::string::npos は、文字列検索で「見つからなかった」ことを表す特別な値です。
find() は、検索した文字列が見つかった場合は位置を返します。
一方、見つからなかった場合は std::string::npos を返します。
そのため、検索結果を使うときは、必ず std::string::npos と比較して、見つかったかどうかを確認する必要があります。
この確認をしないまま検索結果を使うと、意図しない処理になったり、エラーの原因になったりすることがあります。
文字列が含まれているかだけを調べる方法
文字列の中に特定の文字列が含まれているかだけを調べたい場合は、find() の結果が std::string::npos ではないかを確認します。
位置そのものが必要ない場合でも、C++20以前ではこの方法が一般的です。
C++23以降であれば、contains() を使うこともできます。
contains() は、対象の文字列に特定の文字や文字列が含まれているかを真偽値で返す機能です。
ただし、contains() はC++23以降の機能です。
C++17やC++20の環境では使えない場合があるため、幅広い環境に対応するなら find() を使った判定を覚えておくと安心です。
指定した位置から検索する方法
find() では、検索を開始する位置を指定できます。
通常は文字列の先頭から検索しますが、2回目以降の出現を探したい場合や、先頭の一部を検索対象から外したい場合には、開始位置を指定すると便利です。
たとえば、ある単語が文字列の中に複数回出てくる場合、最初に見つかった位置の後ろから再び検索することで、次に出てくる位置を探せます。
この仕組みを使うと、文字列内に同じ単語が何回出てくるかを調べたり、すべての出現位置を取得したりできます。
複数回出現する文字列をすべて検索する方法
find() は、基本的には最初に見つかった位置を返します。
そのため、同じ文字列が複数回含まれている場合、すべての出現位置を調べるには繰り返し検索する必要があります。
最初に検索して見つかった位置を取得し、その次の位置から再度検索します。
これを見つからなくなるまで繰り返すことで、すべての出現位置を調べられます。
ただし、検索開始位置を更新し忘れると、同じ場所を何度も検索してしまい、無限ループの原因になります。
複数回検索する場合は、検索後に開始位置を進めることが重要です。
重複を含めて検索する場合
文字列検索では、重なっている出現を含めるかどうかも考える必要があります。
たとえば、「aaaa」という文字列の中から「aa」を検索する場合を考えます。
重複を含めない場合、見つかる位置は先頭とその次のまとまりになります。
しかし、重複を含める場合は、1文字ずつずらしながら検索する必要があります。
重複を含めたい場合は、見つかった位置のすぐ次から再検索します。
重複を含めたくない場合は、見つかった文字列の長さ分だけ進めてから再検索します。
この違いは、文字列の出現回数を数えるときに重要です。
後ろから検索する方法
文字列を後ろから検索したい場合は、rfind() を使います。
rfind() は、指定した文字や文字列が最後に出てくる位置を探します。
たとえば、文章の中で最後に出てくる単語を調べたい場合や、ファイル名の最後のドットを探して拡張子を取得したい場合に便利です。
通常の find() は前から検索し、rfind() は後ろから検索します。
目的に応じて使い分けるとよいでしょう。
特定の文字のどれかを検索する方法
複数の文字のうち、どれか1つが最初に出てくる位置を探したい場合は、find_first_of() を使います。
たとえば、文字列の中からカンマ、ピリオド、感嘆符、疑問符などの記号を探したい場合に便利です。
find() は特定の文字列をそのまま探しますが、find_first_of() は指定した文字の集合の中から、いずれかに一致する文字を探します。
そのため、「この中のどれかが出てきたら位置を知りたい」という場合に向いています。
指定した文字以外を検索する方法
指定した文字に含まれない文字を探したい場合は、find_first_not_of() を使います。
よくある用途は、文字列の先頭にある空白を無視して、最初の有効な文字を探す処理です。
たとえば、ユーザーが入力した文字列の先頭に空白が含まれている場合、その空白を飛ばして実際の文字が始まる位置を探すことができます。
文字列の整形や入力チェックなどで役立つ機能です。
後ろから指定文字を検索する方法
後ろから特定の文字を探したい場合は、find_last_of() を使います。
find_last_of() は、指定した文字のうち、最後に出てくるものを探します。
たとえば、ファイルパスの中から最後のスラッシュを探し、その後ろにあるファイル名だけを取り出したい場合に便利です。
Windowsではパスの区切りにバックスラッシュが使われることもあります。
一方、Unix系の環境ではスラッシュが使われます。
そのため、両方に対応したい場合は、スラッシュとバックスラッシュの両方を検索対象にすることがあります。
後ろから指定文字以外を検索する方法
文字列の末尾から、指定した文字以外を探したい場合は、find_last_not_of() を使います。
たとえば、文字列の末尾にある空白を削除したいときに使えます。
文章やユーザー入力では、末尾に余分な空白や改行が入ることがあります。
そのような不要な文字を取り除く処理では、最後の空白以外の文字を探し、そこまでを有効な文字列として扱います。
検索結果を使って文字列を切り出す方法
文字列検索は、単に「含まれているか」を調べるだけでなく、文字列を切り出す処理にもよく使われます。
たとえば、メールアドレスからユーザー名とドメインを分けたい場合、まず @ の位置を検索します。
その位置より前をユーザー名、後ろをドメインとして取り出せます。
このように、検索で区切り文字の位置を見つけ、その位置を基準に文字列を分割する処理は非常によく使われます。
URL、ファイルパス、CSV、ログデータなどを扱うときにも役立ちます。
検索して置換する方法
C++の std::string には、単純な文字列をすべて一括置換する専用のメンバ関数はありません。
そのため、特定の文字列を別の文字列に置き換えたい場合は、検索と置換を組み合わせます。
まず置換したい文字列を検索し、見つかった位置に対して置換処理を行います。
1回だけ置換したい場合は、最初に見つかった位置だけを置換します。
すべて置換したい場合は、検索と置換を繰り返します。
ただし、置換前の文字列が空文字列の場合は、意図しない動作になりやすいため注意が必要です。
実用的な処理では、置換前の文字列が空でないかを事前に確認すると安全です。
大文字・小文字を区別せずに検索する方法
通常、std::string::find() は大文字と小文字を区別します。
たとえば、「Apple」と「apple」は別の文字列として扱われます。
そのため、大文字・小文字を無視して検索したい場合は、工夫が必要です。
一般的な方法は、検索対象の文字列と検索したい文字列をどちらも小文字、または大文字に変換してから検索する方法です。
ただし、この方法は英数字中心の文字列では使いやすいものの、日本語やUnicode文字を厳密に扱う場合には注意が必要です。
日本語、全角・半角、アクセント付き文字、絵文字などを含む文字列では、単純な大文字・小文字変換だけでは十分でない場合があります。
std::search()を使う方法
文字列検索には、std::search() を使う方法もあります。
std::search() は、文字列だけでなく、配列や std::vector などの範囲に対しても使える汎用的な検索アルゴリズムです。
通常の文字列検索であれば find() の方が簡単です。
しかし、文字列以外のデータ列を検索したい場合や、より汎用的な処理を書きたい場合には std::search() が便利です。
初心者の場合は、まず find() を優先して覚え、必要に応じて std::search() を学ぶとよいでしょう。
C++23以降ならcontains()も使える
C++23以降では、std::string に contains() が追加されています。
contains() は、指定した文字や文字列が含まれているかどうかを調べるための機能です。
find() は見つかった位置を返しますが、contains() は含まれているかどうかだけを返します。
そのため、位置が不要で、「含まれているかどうか」だけを知りたい場合は、contains() の方が読みやすくなります。
ただし、contains() はC++23以降の機能です。
C++20以前の環境では使えないため、その場合は find() と std::string::npos を使って判定します。
正規表現で文字列を検索する方法
より複雑な条件で文字列を検索したい場合は、正規表現を使います。
正規表現を使うと、単なる部分一致だけでなく、特定のパターンに合う文字列を探せます。
たとえば、次のような検索に向いています。
| 検索したい内容 | 例 |
|---|---|
| 数字を含むか | 商品番号や電話番号の検索 |
| メールアドレスらしい文字列があるか | 問い合わせ文のチェック |
| 郵便番号の形式になっているか | 入力フォームの確認 |
| URLが含まれているか | テキスト内のリンク検出 |
| 特定の形式の日付があるか | ログや文章の解析 |
単純な文字列検索であれば find() で十分です。
しかし、「数字が3桁続く」「英字の後に数字が続く」「メールアドレスのような形式を探す」といった条件では、正規表現が便利です。
ただし、正規表現は便利な反面、複雑になりすぎると読みづらくなります。
単純な検索で済む場合は、無理に正規表現を使わず、find() を使う方がわかりやすいです。
正規表現で一致した文字列を取り出す方法
正規表現では、条件に一致するかどうかを調べるだけでなく、一致した文字列そのものを取り出すこともできます。
たとえば、文章の中から電話番号やメールアドレスだけを取り出したい場合に使えます。
正規表現で検索し、見つかった部分を取得することで、文字列の抽出処理ができます。
ただし、メールアドレスやURLなどの形式は実際には非常に複雑です。
簡単な正規表現で判定できるのは、あくまで簡易的なチェックだと考えた方がよいでしょう。
正規表現で複数の一致を検索する方法
文章の中に複数の数字やメールアドレス、特定のパターンが含まれている場合は、正規表現を使って複数の一致を順番に取り出すことができます。
たとえば、「100円、250円、300円」のような文章から、すべての数字を取り出したい場合に便利です。
このような処理は、ログ解析、入力データのチェック、テキストからの情報抽出などでよく使われます。
日本語文字列を検索する場合の注意点
C++の std::string は、文字列を文字単位ではなくバイト列として扱います。
UTF-8で書かれた日本語文字列でも、完全一致の検索であれば find() で検索できることが多いです。
たとえば、日本語の文章の中から特定の単語を探すような処理は、検索対象と検索語の文字コードが同じであれば問題なく動作するケースが多いです。
ただし、注意したいのは、find() が返す位置です。
UTF-8の日本語は、1文字が複数バイトで表現されます。
そのため、find() が返す位置は「見た目上の文字数」ではなく、「バイト単位の位置」になります。
日本語の何文字目に出てきたかを正確に扱いたい場合は、単純な std::string の位置だけでは不十分な場合があります。
std::wstringで検索する方法
ワイド文字列を扱う場合は、std::wstring でも検索ができます。
std::wstring にも find() などの検索機能があるため、通常の std::string と似た感覚で使えます。
ただし、std::wstring を使えば日本語やUnicodeの扱いがすべて簡単になるわけではありません。
std::wstring で使われる wchar_t のサイズは、環境によって異なることがあります。
たとえば、WindowsとLinuxでは内部表現が異なる場合があります。
そのため、クロスプラットフォームで厳密に日本語やUnicodeを扱う場合は、専用ライブラリの利用を検討することもあります。
単純に「特定の日本語単語が含まれているか」を調べる程度であれば、UTF-8の std::string でも対応できることが多いです。
C文字列で検索する方法
C++では std::string を使うのが一般的ですが、C言語形式の文字列を扱う場面もあります。
C言語形式の文字列とは、文字の配列として扱う文字列のことです。
このような文字列を検索する場合は、C言語由来の検索関数を使うことがあります。
ただし、C++で新しくコードを書く場合は、基本的には std::string を使う方が安全で扱いやすいです。
C形式の文字列は、終端文字やメモリ管理に注意が必要なため、初心者にはやや扱いづらい部分があります。
文字列検索でよくあるミス
C++の文字列検索では、初心者がつまずきやすいポイントがいくつかあります。
検索結果を確認せずに使ってしまう
find() の結果を使う前には、見つかったかどうかを必ず確認する必要があります。
見つからなかった場合は std::string::npos が返されます。
この値を通常の位置として使ってしまうと、意図しない処理やエラーの原因になります。
検索結果を使う前に、std::string::npos ではないかを確認する習慣をつけることが大切です。
位置が0から始まることを忘れる
C++の文字列位置は0から始まります。
そのため、先頭の文字は1番目ではなく0番目です。
検索結果として返ってくる位置も0始まりであることを理解しておきましょう。
大文字・小文字の違いを見落とす
find() は大文字と小文字を区別します。
そのため、「Apple」と「apple」は別の文字列として扱われます。
大文字・小文字を無視して検索したい場合は、事前に小文字または大文字に変換するなどの処理が必要です。
検索開始位置を更新しない
複数回検索する場合、検索開始位置を更新しないと、同じ場所を何度も検索してしまうことがあります。
これにより、無限ループになる可能性があります。
複数の出現位置を調べる場合は、見つかった位置の次から検索するようにすることが重要です。
空文字列の検索を考慮していない
検索語が空文字列の場合、通常の検索とは違った結果になることがあります。
特に、複数回検索や置換処理では、検索語が空だと意図しない動作につながる可能性があります。
実用的なコードでは、検索語や置換前の文字列が空でないかを事前に確認すると安全です。
実用的な文字列検索の使い方
文字列検索は、さまざまな場面で使われます。
メールアドレスの確認
メールアドレスの中に @ が含まれているかを確認する場合、文字列検索を使えます。
ただし、@ が含まれているだけでは、正しいメールアドレスとは限りません。
実際の入力チェックでは、より詳しい条件確認が必要です。
ファイル拡張子の取得
ファイル名の中から最後のドットを探すことで、拡張子を取り出せます。
たとえば、画像ファイルかどうか、テキストファイルかどうかを判定したい場合に使えます。
ただし、ファイル名によってはドットが複数含まれる場合や、先頭がドットの特殊なファイル名もあります。
用途に応じて処理を調整することが大切です。
URLの判定
URLの中に特定の文字列が含まれているかを調べることで、特定のページかどうかを簡易的に判定できます。
たとえば、URLに商品ページを表す文字列が含まれていれば、商品ページとして扱うといった使い方ができます。
ただし、実際のURL判定では、単純な部分一致だけでは不十分な場合があります。パスやクエリパラメータを分解して確認する方が安全です。
CSVや区切り文字の処理
カンマ区切りの文字列から特定の項目を探す場合にも、文字列検索が使えます。
ただし、単純な部分一致では、意図しない項目に一致してしまうことがあります。
たとえば、「app」を検索した場合、「apple」にも一致します。
完全な項目として検索したい場合は、区切り文字を考慮して処理する必要があります。
文字列の前後の空白削除
文字列の前後にある余分な空白を取り除く処理でも、文字列検索が使われます。
先頭から空白以外の文字を探し、末尾から空白以外の文字を探すことで、有効な文字列の範囲を判断できます。
ユーザー入力の整形やデータの前処理でよく使われる考え方です。
目的別の使い分け
C++で文字列を検索するときは、目的に応じて使う機能を選ぶことが大切です。
単純に文字列を探したい場合
特定の文字や文字列が含まれているかを調べたい場合は、find() を使います。
最も基本的で、使用頻度の高い方法です。
含まれているかだけを知りたい場合
含まれているかどうかだけが必要で、位置が不要な場合は、C++23以降であれば contains() が使えます。
C++20以前では、find() と std::string::npos を使って判定します。
最後に出てくる位置を知りたい場合
後ろから検索したい場合や、最後に出てくる位置を知りたい場合は、rfind() を使います。
ファイル名の拡張子や、最後の区切り文字を探すときに便利です。
複数の文字のどれかを探したい場合
複数の候補文字のうち、どれかが出てくる位置を探したい場合は、find_first_of() や find_last_of() を使います。
記号や区切り文字を探す処理に向いています。
空白以外の文字を探したい場合
空白や改行を除いた最初の文字、または最後の文字を探したい場合は、find_first_not_of() や find_last_not_of() を使います。
トリム処理や入力整形でよく使われます。
複雑な条件で検索したい場合
メールアドレス、電話番号、郵便番号、日付、URLなど、特定の形式に一致する文字列を探したい場合は、正規表現を使います。
ただし、単純な検索で済む場合は、find() の方が読みやすく扱いやすいです。
C++の文字列検索で押さえるべきポイント
C++で文字列検索を行うときは、次のポイントを押さえておくと安心です。
基本はfind()を使う
単純な部分一致検索では、まず find() を使います。
find() は、C++の文字列検索で最も基本的な関数です。
文字列が含まれているかを調べたり、出現位置を取得したりできます。
見つからない場合はstd::string::nposになる
find() で検索対象が見つからなかった場合は、std::string::npos が返されます。
検索結果を使う前には、必ず std::string::npos ではないかを確認しましょう。
位置は0から始まる
検索結果として返ってくる位置は0始まりです。
先頭の文字は位置0です。
この点を忘れると、文字列の切り出しや位置の表示でずれが生じることがあります。
日本語ではバイト位置に注意する
UTF-8の日本語文字列を std::string で扱う場合、検索自体はできることが多いです。
ただし、返ってくる位置は見た目上の文字数ではなく、バイト単位の位置になります。
日本語の文字数や表示上の位置を厳密に扱う場合は、文字コードやUnicode処理への理解が必要です。
複数検索では開始位置を更新する
同じ文字列を複数回検索する場合は、検索開始位置を更新する必要があります。
更新しないと、同じ位置を繰り返し検索してしまい、無限ループの原因になります。
contains()はC++23以降
contains() は便利ですが、C++23以降の機能です。
古い環境でも動かしたい場合は、find() を使った判定の方が安全です。
まとめ
C++で文字列を検索する場合、まず覚えるべきなのは std::string::find() です。
find() を使えば、文字列の中に特定の文字や文字列が含まれているかを調べられます。
見つかった場合はその位置を返し、見つからなかった場合は std::string::npos を返します。
後ろから検索したい場合は rfind()、複数の候補文字の中から探したい場合は find_first_of() や find_last_of()、空白以外の文字を探したい場合は find_first_not_of() や find_last_not_of() を使います。
また、C++23以降であれば、含まれているかどうかだけを調べるために contains() を使うこともできます。
ただし、C++20以前では使えないため、基本的には find() と std::string::npos の組み合わせを理解しておくことが重要です。
複雑な条件で検索したい場合は、正規表現を使う方法もあります。
電話番号、メールアドレス、URL、日付など、特定のパターンを探したい場合に便利です。
C++の文字列検索では、単に関数名を覚えるだけでなく、「見つからなかった場合の扱い」「位置が0から始まること」「日本語ではバイト位置になること」「複数検索では開始位置を更新すること」を理解しておくと、実用的な文字列処理ができるようになります。
以上、、C++で文字列を検索する方法についてでした。
最後までお読みいただき、ありがとうございました。
