HOWTO · C

C 言語での正規表現

この記事では、C の正規表現について説明します。

このページの内容

POSIX の正規表現関数を使うと、C プログラムでパターンをコンパイルし、文字列を照合して、各テストが一致したかどうかを確認できます。正規表現は C 言語自体の機能ではありません。この記事では POSIX の <regex.h> インターフェースを使用します。

POSIX を使った C の正規表現

正規表現は、テキスト内のパターンを表します。POSIX には、基本正規表現と拡張正規表現という主な構文が 2 種類あります。以下の例では REG_EXTENDED を指定して拡張構文を使います。

ブラケット式は、指定した集合から 1 文字に一致します。たとえば、[abc] は a、b、c のいずれかに一致し、[[:digit:]] は数字に一致します。[[:alnum:]_] は英数字またはアンダースコアに一致し、[[:lower:]] は現在のロケールで小文字に一致します。POSIX の文字クラスはブラケット式の中に記述する必要があるため、[:number:] や [:word:] は標準のクラスではありません。数字には [[:digit:]] を使い、英字、数字、アンダースコアを含める場合は [[:alnum:]_] を使います。

照合の動作は現在のロケールに依存することがあり、特に文字クラスや大文字小文字の扱いに影響します。アプリケーションでロケール固有の規則が必要な場合は、ロケールを明示的に設定してください。この API は POSIX 実装で提供されますが、C 言語だけで利用が保証されるわけではありません。

regcomp() で POSIX 正規表現をコンパイルする

コンパイル済みの式を格納する regex_t オブジェクトを宣言し、そのアドレス、NUL 終端されたパターン、コンパイルフラグを regcomp() に渡します。REG_EXTENDED を指定すると、+ などの演算子は拡張正規表現の構文として扱われます。大文字小文字を区別せずに照合するには REG_ICASE を追加します。部分一致のオフセットが不要なら REG_NOSUB を追加できます。

コンパイルが成功すると regcomp() は 0 を返します。0 以外の戻り値はエラーコードであり、errno の値ではありません。同じ regex_t オブジェクトを使って regerror() を呼び出すと、診断メッセージを整形できます。コンパイルに成功した場合に限り regfree() を呼び出してください。

regexec() で文字列を照合し、コンパイル済みの正規表現を解放する

コンパイル済みの regex_t と NUL 終端された文字列を regexec() に渡します。戻り値が 0 なら一致し、REG_NOMATCH ならパターンに一致しなかったことを示します。それ以外の値は実行エラーを示し、regerror() で整形できます。部分一致の位置が必要な場合は、regmatch_t 要素の配列とその容量を渡します。最初の要素には全体の一致位置が格納されます。REG_NOSUB を指定した場合は、部分一致の位置を要求しないでください。

以下の完全な例では、1 つのパターンをコンパイルし、2 つの文字列をテストしてから、コンパイル済みオブジェクトを解放します。コンパイル時と実行時の診断には regerror() を使います。提供された正常終了時の実行では、match、続いて no match と表示され、終了コードは 0 でした。コード例は変更されていないため、表示される match と no match のラベルは英語のままです。

この例を実行します:

#include <regex.h>
#include <stddef.h>
#include <stdio.h>

int main(void) {
    regex_t re;
    const char *pattern = "[[:alpha:]]+";
    int status = regcomp(&re, pattern, REG_EXTENDED);

    if (status != 0) {
        char message[256];
        regerror(status, &re, message, sizeof message);
        printf("compile: %s\n", message);
        return 1;
    }

    const char *samples[] = {"C language", "123"};
    for (size_t i = 0; i < sizeof samples / sizeof samples[0]; ++i) {
        status = regexec(&re, samples[i], 0, NULL, 0);
        if (status == 0) {
            puts("match");
        } else if (status == REG_NOMATCH) {
            puts("no match");
        } else {
            char message[256];
            regerror(status, &re, message, sizeof message);
            printf("execution: %s\n", message);
        }
    }

    regfree(&re);
    return 0;
}
match
no match

この例では、戻り値を確認してから使用し、両方の文字列をテストし終えるまでコンパイル済みの式を保持します。提供された実行の終了コードは 0 でした。この例には POSIX の <regex.h> 実装が必要です。