【C言語】複数の文字列を検索する方法を解説

この記事では、基本的なループを使った方法から、配列や構造体を使った方法、さらに効率的な文字列検索アルゴリズムであるKMPアルゴリズムとBoyer-Mooreアルゴリズムまで、さまざまな検索方法をわかりやすく解説します。

また、実際にファイル内や複数ファイルに対して文字列を検索する実践的な応用例も紹介します。

初心者の方でも理解しやすいように、サンプルコードとその実行結果を交えて説明しますので、ぜひ参考にしてください。

目次から探す

複数の文字列を検索する方法

C言語で複数の文字列を検索する方法にはいくつかのアプローチがあります。

ここでは、単純なループを使った方法、配列を使った方法、そして構造体を使った方法について解説します。

単純なループを使った検索

まずは、最も基本的な方法である単純なループを使った検索方法を見てみましょう。

この方法は、文字列の配列を一つずつチェックしていくというものです。

#include <stdio.h>
#include <string.h>
int main() {
    char *strings[] = {"apple", "banana", "cherry", "date"};
    char *search = "banana";
    int found = 0;
    for (int i = 0; i < 4; i++) {
        if (strcmp(strings[i], search) == 0) {
            printf("Found %s at index %d\n", search, i);
            found = 1;
            break;
        }
    }
    if (!found) {
        printf("%s not found\n", search);
    }
    return 0;
}

このコードでは、stringsという文字列の配列を定義し、searchという文字列を探しています。

strcmp関数を使って各文字列とsearchを比較し、一致するものが見つかればそのインデックスを表示します。

配列を使った検索

次に、配列を使った検索方法を見てみましょう。

この方法では、複数の文字列を配列に格納し、ループを使って検索を行います。

#include <stdio.h>
#include <string.h>
int main() {
    char strings[4][10] = {"apple", "banana", "cherry", "date"};
    char search[10] = "cherry";
    int found = 0;
    for (int i = 0; i < 4; i++) {
        if (strcmp(strings[i], search) == 0) {
            printf("Found %s at index %d\n", search, i);
            found = 1;
            break;
        }
    }
    if (!found) {
        printf("%s not found\n", search);
    }
    return 0;
}

このコードでは、stringsという2次元配列を使って文字列を格納しています。

searchという文字列を探し、strcmp関数を使って各文字列と比較します。

構造体を使った検索

最後に、構造体を使った検索方法を見てみましょう。

この方法では、文字列とその関連情報を構造体に格納し、検索を行います。

#include <stdio.h>
#include <string.h>
typedef struct {
    char name[10];
    int id;
} Fruit;
int main() {
    Fruit fruits[4] = {{"apple", 1}, {"banana", 2}, {"cherry", 3}, {"date", 4}};
    char search[10] = "date";
    int found = 0;
    for (int i = 0; i < 4; i++) {
        if (strcmp(fruits[i].name, search) == 0) {
            printf("Found %s with ID %d\n", search, fruits[i].id);
            found = 1;
            break;
        }
    }
    if (!found) {
        printf("%s not found\n", search);
    }
    return 0;
}

このコードでは、Fruitという構造体を定義し、fruitsという構造体の配列を使って文字列とそのIDを格納しています。

searchという文字列を探し、strcmp関数を使って各構造体のnameフィールドと比較します。

以上の方法を使えば、C言語で複数の文字列を効率的に検索することができます。

それぞれの方法には利点と欠点があるため、用途に応じて適切な方法を選択してください。

効率的な文字列検索アルゴリズム

文字列検索はプログラミングにおいて非常に重要な操作の一つです。

特に、大量のデータを扱う場合、効率的なアルゴリズムを使用することで検索速度を大幅に向上させることができます。

ここでは、代表的な効率的な文字列検索アルゴリズムであるKMPアルゴリズムとBoyer-Mooreアルゴリズムについて解説します。

KMPアルゴリズム

KMP(Knuth-Morris-Pratt)アルゴリズムは、部分一致の情報を利用して検索を効率化するアルゴリズムです。

部分一致の情報を事前に計算しておくことで、検索中に無駄な比較を避けることができます。

KMPアルゴリズムの基本概念

KMPアルゴリズムは、検索する文字列(パターン)に対して部分一致テーブル(prefix table)を作成します。

このテーブルは、パターンの各位置における部分一致の長さを示します。

検索中に一致しない文字が見つかった場合、このテーブルを参照して次の比較位置を決定します。

KMPアルゴリズムの実装例

以下に、KMPアルゴリズムを用いた文字列検索のサンプルコードを示します。

#include <stdio.h>
#include <string.h>
// 部分一致テーブルを作成する関数
void computeLPSArray(char* pat, int M, int* lps) {
    int len = 0;
    lps[0] = 0;
    int i = 1;
    while (i < M) {
        if (pat[i] == pat[len]) {
            len++;
            lps[i] = len;
            i++;
        } else {
            if (len != 0) {
                len = lps[len - 1];
            } else {
                lps[i] = 0;
                i++;
            }
        }
    }
}
// KMPアルゴリズムによる文字列検索
void KMPSearch(char* pat, char* txt) {
    int M = strlen(pat);
    int N = strlen(txt);
    int lps[M];
    computeLPSArray(pat, M, lps);
    int i = 0;
    int j = 0;
    while (i < N) {
        if (pat[j] == txt[i]) {
            j++;
            i++;
        }
        if (j == M) {
            printf("Found pattern at index %d\n", i - j);
            j = lps[j - 1];
        } else if (i < N && pat[j] != txt[i]) {
            if (j != 0) {
                j = lps[j - 1];
            } else {
                i++;
            }
        }
    }
}
int main() {
    char txt[] = "ABABDABACDABABCABAB";
    char pat[] = "ABABCABAB";
    KMPSearch(pat, txt);
    return 0;
}

このコードでは、computeLPSArray関数が部分一致テーブルを作成し、KMPSearch関数が実際の検索を行います。

実行結果は以下のようになります。

Found pattern at index 10

Boyer-Mooreアルゴリズム

Boyer-Mooreアルゴリズムは、検索する文字列の末尾から比較を行うことで効率的に検索を行うアルゴリズムです。

このアルゴリズムは、パターンの末尾から前方に向かって比較を行い、不一致が見つかった場合に大きくスキップすることができます。

Boyer-Mooreアルゴリズムの基本概念

Boyer-Mooreアルゴリズムは、以下の2つのヒューリスティックを利用します。

  1. Bad Character Heuristic: 不一致が見つかった場合、不一致の文字がパターン内に存在するかどうかを確認し、存在する場合はその位置までスキップします。
  2. Good Suffix Heuristic: パターンの末尾部分が一致した場合、その部分がパターン内の他の位置に一致するかどうかを確認し、一致する場合はその位置までスキップします。

Boyer-Mooreアルゴリズムの実装例

以下に、Boyer-Mooreアルゴリズムを用いた文字列検索のサンプルコードを示します。

#include <stdio.h>
#include <string.h>
#define NO_OF_CHARS 256
// Bad Character Heuristicのテーブルを作成する関数
void badCharHeuristic(char *str, int size, int badchar[NO_OF_CHARS]) {
    int i;
    for (i = 0; i < NO_OF_CHARS; i++)
        badchar[i] = -1;
    for (i = 0; i < size; i++)
        badchar[(int) str[i]] = i;
}
// Boyer-Mooreアルゴリズムによる文字列検索
void search(char *txt, char *pat) {
    int m = strlen(pat);
    int n = strlen(txt);
    int badchar[NO_OF_CHARS];
    badCharHeuristic(pat, m, badchar);
    int s = 0;
    while (s <= (n - m)) {
        int j = m - 1;
        while (j >= 0 && pat[j] == txt[s + j])
            j--;
        if (j < 0) {
            printf("Found pattern at index %d\n", s);
            s += (s + m < n) ? m - badchar[txt[s + m]] : 1;
        } else
            s += (j - badchar[txt[s + j]] > 1) ? j - badchar[txt[s + j]] : 1;
    }
}
int main() {
    char txt[] = "ABAAABCD";
    char pat[] = "ABC";
    search(txt, pat);
    return 0;
}

このコードでは、badCharHeuristic関数がBad Character Heuristicのテーブルを作成し、search関数が実際の検索を行います。

実行結果は以下のようになります。

Found pattern at index 4

以上が、KMPアルゴリズムとBoyer-Mooreアルゴリズムの基本的な解説と実装例です。

これらのアルゴリズムを理解し、適切に使い分けることで、効率的な文字列検索を実現することができます。

実践的な応用例

ファイル内の文字列検索

ファイル内の文字列検索は、特定のテキストファイルから特定の文字列を探し出す作業です。

C言語では、ファイル操作のための標準ライブラリ関数を使用して、ファイルを開き、読み込み、文字列を検索することができます。

以下に、ファイル内の文字列を検索するサンプルコードを示します。

#include <stdio.h>
#include <string.h>
#define MAX_LINE 256
int main() {
    FILE *file;
    char line[MAX_LINE];
    char *filename = "example.txt";
    char *search = "target";
    // ファイルを開く
    file = fopen(filename, "r");
    if (file == NULL) {
        printf("ファイルを開けませんでした。\n");
        return 1;
    }
    // ファイルの各行を読み込み、検索文字列を探す
    while (fgets(line, MAX_LINE, file) != NULL) {
        if (strstr(line, search) != NULL) {
            printf("見つかりました: %s", line);
        }
    }
    // ファイルを閉じる
    fclose(file);
    return 0;
}

このプログラムは、example.txtというファイルを開き、各行を読み込んでtargetという文字列を検索します。

見つかった行があれば、その行を表示します。

実行結果の例

見つかりました: This is the target line.

複数ファイルに対する文字列検索

複数のファイルに対して文字列を検索する場合、ディレクトリ内のファイルを順次開いて検索を行う必要があります。

C言語では、ディレクトリ操作のためのライブラリ関数を使用して、ディレクトリ内のファイルをリストアップし、それぞれのファイルに対して文字列検索を行うことができます。

以下に、複数ファイルに対する文字列検索のサンプルコードを示します。

#include <stdio.h>
#include <string.h>
#include <dirent.h>
#define MAX_LINE 256
void search_in_file(const char *filename, const char *search) {
    FILE *file;
    char line[MAX_LINE];
    // ファイルを開く
    file = fopen(filename, "r");
    if (file == NULL) {
        printf("ファイルを開けませんでした: %s\n", filename);
        return;
    }
    // ファイルの各行を読み込み、検索文字列を探す
    while (fgets(line, MAX_LINE, file) != NULL) {
        if (strstr(line, search) != NULL) {
            printf("見つかりました: %s - %s", filename, line);
        }
    }
    // ファイルを閉じる
    fclose(file);
}
int main() {
    DIR *dir;
    struct dirent *entry;
    char *directory = "./";
    char *search = "target";
    // ディレクトリを開く
    dir = opendir(directory);
    if (dir == NULL) {
        printf("ディレクトリを開けませんでした。\n");
        return 1;
    }
    // ディレクトリ内の各ファイルに対して検索を行う
    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_type == DT_REG) { // 通常のファイルのみを対象とする
            search_in_file(entry->d_name, search);
        }
    }
    // ディレクトリを閉じる
    closedir(dir);
    return 0;
}

このプログラムは、現在のディレクトリ内のすべてのファイルに対してtargetという文字列を検索します。

見つかった場合は、ファイル名と該当する行を表示します。

実行結果の例

見つかりました: file1.txt - This is the target line in file1.
見つかりました: file2.txt - Another target line in file2.

このように、C言語を使ってファイル内および複数ファイルに対する文字列検索を行うことができます。

これらの方法を応用することで、より複雑な検索処理やデータ解析を行うことが可能です。

目次から探す