【C言語入門】文字列内の検索方法まとめ(文字指定、正規表現)

文字列の検索って使ってますか?

ある決められた形式の文字列から指定した文字や文字列が含まれる箇所を探しだし、処理を行いたい場合ってありますよね。

たとえばテキストエディタやhtmlファイル内で指定の文字や文字列を探す場合などです。

この記事では、文字列の検索について

・検索とは
・検索方法について

という基本的な内容から、

・正規表現での検索方法について

など応用的な使い方の内容についても解説していきます。

今回は文字列の検索について、使い方をわかりやすく解説します!

目次

検索とは

文字列の検索とは、ある文字列の中から別のある文字列を検索することです。

ある決められた形式の文字列から指定した文字や文字列が含まれる箇所を探す場合に行います。

検索方法について

文字列内を検索する方法として、指定文字を検索する方法と指定文字列を検索する方法があります。

C言語では指定文字を検索する方法としてstrchr関数が、指定文字列を検索する方法としてstrstr関数が用意されています。

どちらもヘッダーファイル「string.h」をインクルードして使用します。

それぞれの使い方についてみていきましょう。

文字列内の文字を検索する方法について

strchr関数を使用して指定文字を検索します。

strchr関数は第1引数に検索される文字列のアドレスを、第2引数に指定文字を入力します。

ちなみに第2引数の型指定はint型です。

strchr関数は該当文字のアドレスを返します。

第1引数に指定した文字列内に第2引数で指定した文字が含まれない場合はNULLを返します。

それではサンプルコードで確認していきましょう。

#include <stdio.h>
#include <string.h>
 
int main(void) {
    char str[] = "100-0005"; //郵便番号の形式
    char *adr1, *adr2;

    // 指定文字(-)での文字列検索
    adr1 = strchr(str, (int)'-');
    printf("文字列の検索結果: %s\n", adr1);

    // 指定文字(a)での文字列検索(該当文字なしの場合)
    adr2 = strchr(str, (int)'a');
    printf("文字列の検索結果: %s\n", adr2);
    
    return 0;
}

実行結果:

文字列の検索結果: -0005
文字列の検索結果: (null)

このサンプルコードではchar型の文字列「str」内をstrchr関数を使って検索しています。

文字「-」で検索した結果をchar型のポインタ「adr1」に返し、文字「a」で検索した結果を「adr2」に返しています。

文字「-」で検索した場合、「str」内に「-」が含まれるので「-」のアドレスをポインタ「adr1」に返し、「-」から終端文字NULLまで表示しています。

文字「a」で検索した場合、「str」内に「a」が含まれませんのでポインタ「adr2」にはNULLを返しています

文字列内の文字列を検索する方法について

strstr関数を使用して指定文字列を検索します。

strstr関数は第1引数に検索される文字列のアドレスを、第2引数に指定文字列を入力します。

strchr関数は該当文字列の先頭のアドレスを返します。

第1引数に指定した文字列内に第2引数で指定した文字列が含まれない場合はNULLを返します。

それではサンプルコードで確認していきましょう。

#include <stdio.h>
#include <string.h>
 
int main(void) {
    char str[] = "〒100-0005 東京都千代田区丸の内1丁目"; //郵便番号 住所の形式
    char *adr1;
    char *adr2;

    // 指定文字列(東京都)での文字列検索
    adr1 = strstr(str, "東京都");
    printf("文字列の検索結果: %s\n", adr1);

    // 指定文字列(大阪府)での文字列検索(該当文字列なしの場合)
    adr2 = strstr(str, "大阪府");
    printf("文字列の検索結果: %s\n", adr2);
    
    return 0;
}

実行結果:

文字列の検索結果: 東京都千代田区丸の内1丁目
文字列の検索結果: (null)

このサンプルコードではchar型の文字列「str」内をstrstr関数を使って検索しています。

文字列「東京都」で検索した結果をchar型のポインタ「adr1」に返し、文字列「大阪府」で検索した結果を「adr2」に返しています。

文字列「東京都」で検索した場合、「str」内に「東京都」が含まれるので「東京都」の先頭のアドレスをポインタ「adr1」に返し、「東京都」から終端文字NULLまで表示しています。

文字列「大阪府」で検索した場合、「str」内に「大阪府」が含まれませんのでポインタ「adr2」にはNULLを返しています

正規表現での検索方法について

C言語では正規表現を使って文字列内を検索することができます。

正規表現の書き方と正規表現での検索方法についてみていきましょう。

正規表現の書き方について

正規表現とはいくつかの文字列を一つの形式でまとめて表現するための表現方法のことです。

主な正規表現については下記のとおりになります。

正規表現:

記号記号の説明例の説明
.任意の1文字。改行文字は除く。.+任意の文字列
*直前の1文字の0回以上の繰り返しと一致hoge*hogeもしくはhogee...と一致
^行の先頭^[0-9]行頭が数字
$行の末尾^.{10}$10文字の行
[ ]カッコ内の任意の1文字と一致。「-」で範囲指定可。[a-z]小文字のアルファベット1文字と一致
[^ ]カッコ内の任意の1文字と不一致。「-」で範囲指定可。[^A-Z]大文字のアルファベット以外
+直前の文字の1個以上の繰り返しと一致hoge+hogee...と一致
?直前の文字が0個または1個の場合に一致hoge?hogeもしくはhogと一致
{ }カッコ内の数値の繰り返しと一致{n}直前の文字のn個の繰り返しと一致
同上{,n}直前の文字のn個以下の繰り返しと一致
同上{m,}直前の文字のm個以上の繰り返しと一致
同上{m,n}直前の文字のm個以上、n個以下の繰り返しと一致
|直前、直後どちらかのパターンに一致hoge|piyohogeまたはpiyo
( )カッコ内をグループ化。マッチした内容は参照可。

正規表現を使った検索方法について

C言語で正規表現を使った文字列内の検索を行うには、ヘッダーファイル「regex.h」をインクルードする必要があります。

Windows環境下では「regex.h」やこれに関連するライブラリがインストールされていない場合もありますので、その場合は使っている環境にあわせて用意をする必要があります。

例えばMinGW(Minimalist GNU for Windows)を使用している場合は、sorceforgeからインクルードファイル、ライブラリファイルなどのダウンロードが可能です。

正規表現を使った検索を行うには、正規表現のオブジェクトを格納するregex_t型の構造体と、正規表現にマッチしたインデックスを格納するregmatch_t型の構造体の配列が必要となります。

また次の3つの関数を使用します。

regcomp:

/* 正規表現のコンパイル。成功時には0(ゼロ)を返す */
int regcomp(regex_t *preg, const char *regex, int cflags)
/* cflags には以下に示す定数を1つ以上「|」(OR)記号を使って指定
 * REG_EXTENDED (regexにPOSIX拡張正規表現を使用。デフォルトはPOSIX標準正規表現を使用。)
 * REG_ICASE (大文字小文字の違いを無視)
 * REG_NOSUB (regexecの引数nmatch、pmatchは無視)
 * REG_NEWLINE (オペレータに改行をマッチさせない) */

regexec:

/* 正規表現による検索を実行 */
int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
/* eflags には以下に示す定数を1つ以上「|」(OR)記号を使って指定
 * REG_NOTBOL (行頭にマッチするオペレータは必ずマッチに失敗する)
 * REG_NOTEOL (行末にマッチするオペレータは必ずマッチに失敗する) */

regfree:

/* regex_t型のオブジェクトのメモリを解放 */
void regfree(regex_t *preg)

それではサンプルコードで確認していきましょう。

#include <stdio.h>
#include <regex.h>
 
int main(void) {
    char str[] = "〒100-0005 東京都千代田区丸の内1丁目"; // 入力文字列
    regex_t preg; // 正規表現のオブジェクト
    size_t num = 5;
    regmatch_t pmatch[num]; // 正規表現にマッチしたインデックスを格納する構造体の配列
    
    // 郵便番号 住所の形式から郵便番号の前半3桁と後半4桁および住所を検索
    const char pattern[] = "〒([0-9]{3})-([0-9]{4}) (.+)"; // マッチする文字列
    
    // 正規表現のコンパイル
    if (regcomp(&preg, pattern, REG_EXTENDED|REG_NEWLINE) != 0) {
        printf("正規表現のコンパイルに失敗しました\n");
        return -1;
    }
    
    // 入力文字列の出力表示
    printf("入力文字列は: %s\n", str);
    
    // 正規表現による検索
    if (regexec(&preg, str, num, pmatch, 0) != 0) {
        printf("マッチしませんでした\n");
    } else {
        for (int i = 0; i < num; i++) {
            if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0) {
                // マッチしたインデックスと文字列の表示
                printf("マッチしたインデックスは%d~%d, str: ", (int)pmatch[i].rm_so, (int)pmatch[i].rm_eo);
                for (int j = pmatch[i].rm_so ; j < pmatch[i].rm_eo; j++) {
                    putchar(str[j]);
                }
            }
            printf("\n");
        }
    }
    
    // オブジェクトのメモリ開放
    regfree(&preg);
    
    return 0;
}

実行結果:

入力文字列は: 〒100-0005 東京都千代田区丸の内1丁目
マッチしたインデックスは0~51, str: 〒100-0005 東京都千代田区丸の内1丁目
マッチしたインデックスは3~6, str: 100
マッチしたインデックスは7~11, str: 0005
マッチしたインデックスは12~51, str: 東京都千代田区丸の内1丁目

このサンプルコードではchar型の文字列「str」内をを正規表現の文字列「pattern」 で検索しています。

regmatch_t型のオブジェクトの配列には要素が5つ格納されるように記述しています。

regcomp関数を使って 正規表現のコンパイルを行っています。

コンパイルが成功すると、regexec関数を使って正規表現による検索を行っています。

検索の結果マッチしていると、それぞれのregmatch_t型のオブジェクトからメンバ「rm_so」を使ってマッチした文字列の先頭のインデックスの値と、メンバ「rm_eo」を使って終端のインデックスの値を呼び出しています。

先頭のインデックスの値から終端のインデックスの値を元に1文字ずつ文字を表示することで、正規表現にマッチした文字列を出力表示しています。

文字列の使い方総まとめ

この記事では紹介しきれなかった文字列のいろいろな使い方を次の記事にまとめているので、ぜひ確認してください!

まとめ

ここでは、文字列の検索について説明しました。

短い文字列から1つの指定文字・文字列を検索するような簡単な検索であれば、strchrおよびstrstrを使うと便利かと思います。

形式が決まっていて指定文字・文字列が複数で多い場合などは正規表現を使う方が便利です。

それぞれを使いこなすことができるように、この記事を何度も参考にして下さいね!

この記事を書いた人

【プロフィール】
DX認定取得事業者に選定されている株式会社SAMURAIのマーケティング・コミュニケーション部が運営。「質の高いIT教育を、すべての人に」をミッションに、IT・プログラミングを学び始めた初学者の方に向け記事を執筆。
累計指導者数4万5,000名以上のプログラミングスクール「侍エンジニア」、累計登録者数1万8,000人以上のオンライン学習サービス「侍テラコヤ」で扱う教材開発のノウハウ、2013年の創業から運営で得た知見に基づき、記事の執筆だけでなく編集・監修も担当しています。
【専門分野】
IT/Web開発/AI・ロボット開発/インフラ開発/ゲーム開発/AI/Webデザイン

目次