【C言語】指定した文字列が何文字目にあるのか検索する方法

この記事では、標準ライブラリの便利な関数strstrstrchrの使い方から、自分で関数を作る方法まで、初心者にもわかりやすく解説します。

さらに、応用例やエラーハンドリングについても触れていますので、これを読めば文字列検索の基本から応用までしっかりと理解できます。

目次から探す

標準ライブラリを使った文字列検索

C言語には、文字列を検索するための便利な標準ライブラリ関数がいくつか用意されています。

ここでは、その中でも特に頻繁に使用されるstrstr関数strchr関数について解説します。

strstr関数の使い方

strstr関数の概要

strstr関数は、ある文字列の中から特定の部分文字列を検索するための関数です。

この関数は、検索対象の文字列の中で最初に見つかった部分文字列の位置を返します。

もし部分文字列が見つからなかった場合は、NULLポインタを返します。

関数のプロトタイプは以下の通りです。

char *strstr(const char *haystack, const char *needle);
  • haystack: 検索対象の文字列
  • needle: 検索する部分文字列

strstr関数の使用例

以下に、strstr関数を使った具体的な例を示します。

#include <stdio.h>
#include <string.h>
int main() {
    const char *haystack = "Hello, world!";
    const char *needle = "world";
    char *result;
    result = strstr(haystack, needle);
    if (result != NULL) {
        printf("部分文字列 '%s' は文字列 '%s' の %ld 文字目にあります。\n", needle, haystack, result - haystack + 1);
    } else {
        printf("部分文字列 '%s' は文字列 '%s' に見つかりませんでした。\n", needle, haystack);
    }
    return 0;
}

このプログラムを実行すると、以下のような出力が得られます。

部分文字列 'world' は文字列 'Hello, world!' の 8 文字目にあります。

strchr関数の使い方

strchr関数の概要

strchr関数は、文字列の中から特定の文字を検索するための関数です。

この関数は、検索対象の文字列の中で最初に見つかった文字の位置を返します。

もし文字が見つからなかった場合は、NULLポインタを返します。

関数のプロトタイプは以下の通りです。

char *strchr(const char *str, int c);
  • str: 検索対象の文字列
  • c: 検索する文字(int型で指定)

strchr関数の使用例

以下に、strchr関数を使った具体的な例を示します。

#include <stdio.h>
#include <string.h>
int main() {
    const char *str = "Hello, world!";
    char ch = 'w';
    char *result;
    result = strchr(str, ch);
    if (result != NULL) {
        printf("文字 '%c' は文字列 '%s' の %ld 文字目にあります。\n", ch, str, result - str + 1);
    } else {
        printf("文字 '%c' は文字列 '%s' に見つかりませんでした。\n", ch, str);
    }
    return 0;
}

このプログラムを実行すると、以下のような出力が得られます。

文字 'w' は文字列 'Hello, world!' の 8 文字目にあります。

以上が、strstr関数strchr関数を使った文字列検索の方法です。

これらの関数を使うことで、簡単に文字列や文字の位置を特定することができます。

自作関数での文字列検索

自作関数の必要性

標準ライブラリの関数であるstrstrstrchrは非常に便利ですが、特定の要件に応じてカスタマイズが必要な場合があります。

例えば、部分一致ではなく完全一致を求める場合や、特定の条件下での検索を行いたい場合などです。

こうした場合には、自作関数を作成することで柔軟に対応することができます。

自作関数の設計

自作関数を設計する際には、以下のポイントを考慮する必要があります。

関数のプロトタイプ宣言

関数のプロトタイプ宣言は、関数の名前、引数の型と数、戻り値の型を定義します。

例えば、文字列中の部分文字列の位置を検索する関数のプロトタイプは以下のようになります。

int findSubstring(const char *str, const char *substr);

関数の引数と戻り値

  • 引数:
  • str: 検索対象の文字列
  • substr: 検索する部分文字列
  • 戻り値:
  • 部分文字列が見つかった場合、その開始位置のインデックス(0から始まる)
  • 見つからなかった場合、-1

自作関数の実装

ループを使った検索方法

自作関数では、ループを使って文字列を一文字ずつチェックし、部分文字列が一致するかどうかを確認します。

以下にその実装例を示します。

#include <stdio.h>
int findSubstring(const char *str, const char *substr) {
    int i, j;
    int str_len = 0, substr_len = 0;
    // 文字列の長さを計算
    while (str[str_len] != '\0') str_len++;
    while (substr[substr_len] != '\0') substr_len++;
    // ループを使って検索
    for (i = 0; i <= str_len - substr_len; i++) {
        for (j = 0; j < substr_len; j++) {
            if (str[i + j] != substr[j]) {
                break;
            }
        }
        if (j == substr_len) {
            return i; // 部分文字列が見つかった位置を返す
        }
    }
    return -1; // 見つからなかった場合
}
int main() {
    const char *str = "Hello, world!";
    const char *substr = "world";
    int index = findSubstring(str, substr);
    if (index != -1) {
        printf("部分文字列は %d 文字目にあります。\n", index);
    } else {
        printf("部分文字列は見つかりませんでした。\n");
    }
    return 0;
}

部分文字列の比較方法

部分文字列の比較は、ループ内で一文字ずつ行います。

str[i + j]substr[j]を比較し、一致しない場合は内側のループを抜けて次の位置から再度比較を開始します。

インデックスの計算方法

インデックスの計算は、外側のループのインデックスiを基準に行います。

部分文字列が一致した場合、その開始位置iを返します。

見つからなかった場合は-1を返します。

このようにして、自作関数を使って文字列中の部分文字列の位置を検索することができます。

標準ライブラリの関数では対応できない特定の要件に対しても、柔軟に対応することが可能です。

応用例

複数の出現箇所を検索する方法

文字列内で特定の部分文字列が複数回出現する場合、それぞれの出現箇所をすべて見つけたいことがあります。

標準ライブラリのstrstr関数を使って、これを実現する方法を見てみましょう。

以下のコードは、文字列内のすべての出現箇所を検索する例です。

#include <stdio.h>
#include <string.h>
void findAllOccurrences(const char *str, const char *sub) {
    const char *temp = str;
    int index;
    while ((temp = strstr(temp, sub)) != NULL) {
        index = temp - str;
        printf("Found at index: %d\n", index);
        temp++; // 次の検索を開始する位置を更新
    }
}
int main() {
    const char *str = "This is a test. This test is simple.";
    const char *sub = "test";
    findAllOccurrences(str, sub);
    return 0;
}

このコードでは、strstr関数を使って部分文字列subの出現箇所を見つけ、見つかった位置を表示しています。

tempポインタを更新することで、次の検索を開始する位置を調整しています。

大文字小文字を区別しない検索方法

C言語の標準ライブラリには、大文字小文字を区別しない文字列検索関数は含まれていません。

しかし、自作関数を使ってこれを実現することができます。

以下のコードは、大文字小文字を区別しない文字列検索を行う例です。

#include <stdio.h>
#include <string.h>
#include <ctype.h>
char *strcasestr(const char *haystack, const char *needle) {
    if (!*needle) return (char *)haystack;
    for (; *haystack; haystack++) {
        if (tolower((unsigned char)*haystack) == tolower((unsigned char)*needle)) {
            const char *h, *n;
            for (h = haystack, n = needle; *h && *n; h++, n++) {
                if (tolower((unsigned char)*h) != tolower((unsigned char)*n)) break;
            }
            if (!*n) return (char *)haystack;
        }
    }
    return NULL;
}
int main() {
    const char *str = "This is a Test. This test is simple.";
    const char *sub = "test";
    char *result = strcasestr(str, sub);
    if (result) {
        printf("Found at index: %ld\n", result - str);
    } else {
        printf("Not found\n");
    }
    return 0;
}

このコードでは、strcasestrという自作関数を使って、大文字小文字を区別しない文字列検索を行っています。

tolower関数を使って、文字を小文字に変換して比較しています。

正規表現を使った高度な検索方法

C言語の標準ライブラリには正規表現を扱う機能は含まれていませんが、POSIXライブラリを使うことで正規表現を利用することができます。

以下のコードは、正規表現を使った文字列検索の例です。

#include <stdio.h>
#include <regex.h>
void findRegex(const char *str, const char *pattern) {
    regex_t regex;
    regmatch_t match[1];
    if (regcomp(®ex, pattern, REG_EXTENDED) != 0) {
        printf("Could not compile regex\n");
        return;
    }
    const char *p = str;
    while (regexec(®ex, p, 1, match, 0) == 0) {
        printf("Found at index: %ld\n", match[0].rm_so + (p - str));
        p += match[0].rm_eo;
    }
    regfree(®ex);
}
int main() {
    const char *str = "This is a test. This test is simple.";
    const char *pattern = "test";
    findRegex(str, pattern);
    return 0;
}

このコードでは、POSIXの正規表現ライブラリを使って、文字列内の正規表現パターンに一致する部分を検索しています。

regcomp関数で正規表現をコンパイルし、regexec関数で検索を行っています。

見つかった位置を表示し、次の検索を行うためにポインタを更新しています。

これらの応用例を使うことで、C言語での文字列検索の幅が広がります。

特定の要件に応じて、適切な方法を選択してください。

エラーハンドリング

C言語で文字列検索を行う際には、エラーハンドリングが非常に重要です。

エラーハンドリングを適切に行うことで、プログラムの信頼性と安定性を向上させることができます。

ここでは、NULLポインタの扱いと検索結果が見つからない場合の処理について詳しく解説します。

NULLポインタの扱い

NULLポインタは、ポインタが有効なメモリアドレスを指していないことを示す特別な値です。

文字列検索関数にNULLポインタを渡すと、プログラムがクラッシュする可能性があります。

したがって、関数を呼び出す前にNULLポインタのチェックを行うことが重要です。

以下に、strstr関数を使用する際のNULLポインタのチェック例を示します。

#include <stdio.h>
#include <string.h>
int main() {
    char *haystack = "Hello, World!";
    char *needle = "World";
    char *result;
    // NULLポインタのチェック
    if (haystack == NULL || needle == NULL) {
        printf("Error: NULL pointer detected.\n");
        return 1;
    }
    result = strstr(haystack, needle);
    if (result != NULL) {
        printf("Found at position: %ld\n", result - haystack);
    } else {
        printf("Not found.\n");
    }
    return 0;
}

この例では、haystackneedleがNULLポインタでないことを確認しています。

NULLポインタが検出された場合、エラーメッセージを表示してプログラムを終了します。

検索結果が見つからない場合の処理

文字列検索を行った結果、指定した文字列が見つからない場合も考慮する必要があります。

strstr関数strchr関数は、検索結果が見つからない場合にNULLポインタを返します。

この場合も適切なエラーハンドリングを行うことが重要です。

以下に、strchr関数を使用する際の検索結果が見つからない場合の処理例を示します。

#include <stdio.h>
#include <string.h>
int main() {
    char *haystack = "Hello, World!";
    char needle = 'x';
    char *result;
    result = strchr(haystack, needle);
    if (result != NULL) {
        printf("Found at position: %ld\n", result - haystack);
    } else {
        printf("Character '%c' not found.\n", needle);
    }
    return 0;
}

この例では、strchr関数を使用して文字'x'を検索しています。

検索結果が見つからない場合、NULLポインタが返されるため、その場合には Character 'x' not found. というメッセージを表示します。

エラーハンドリングを適切に行うことで、プログラムが予期しない動作をすることを防ぎ、ユーザーに対して適切なフィードバックを提供することができます。

これにより、プログラムの信頼性とユーザーエクスペリエンスが向上します。

目次から探す