HOWTO · C

C 語言中的正規表示式

在本文中,我們將討論 C 語言中的正規表示式。

本頁內容

POSIX 正規表示式函式可讓 C 程式編譯模式、測試字串,並判斷每次測試是否符合。正規表示式不是 C 語言本身的一部分;本文使用 POSIX 的 <regex.h> 介面。

C 語言中的 POSIX 正規表示式

正規表示式用來描述文字中的模式。POSIX 提供兩種主要的模式語法:基本正規表示式與延伸正規表示式。下方範例透過 REG_EXTENDED 選用延伸語法。

方括號運算式會比對集合中的單一字元。例如,[abc] 可比對 a、b 或 c;[[:digit:]] 可比對數字;[[:alnum:]_] 可比對英數字元或底線;[[:lower:]] 則會依目前的地區設定比對小寫字母。POSIX 字元類別必須寫在方括號運算式內,因此 [:number:] 和 [:word:] 這類形式並非標準字元類別。要比對數字,請使用 [[:digit:]];若要比對字母、數字和底線,請使用 [[:alnum:]_]。

比對行為可能受目前的地區設定影響,尤其是字元類別與大小寫折疊。若應用程式需要依地區設定採用特定規則,請明確設定地區設定。POSIX 實作提供此 API,但 C 語言本身不保證提供它。

使用 regcomp() 編譯 POSIX 正規表示式

宣告 regex_t 物件來存放編譯後的表示式,然後將它的位址、以 NUL 結尾的模式,以及編譯旗標傳給 regcomp()。使用 REG_EXTENDED 時,+ 等運算子會採用延伸正規表示式語法。若要忽略大小寫進行比對,可加上 REG_ICASE;若不需要子比對位移量,則可加上 REG_NOSUB。

regcomp() 在編譯成功時會回傳 0。非零回傳值是錯誤碼,並不是 errno 值。請使用相同的 regex_t 物件呼叫 regerror(),以產生診斷訊息。只有在編譯成功後才能呼叫 regfree()。

使用 regexec() 比對字串並釋放已編譯的正規表示式

呼叫 regexec() 時,傳入已編譯的 regex_t 和以 NUL 結尾的字串。回傳值 0 代表符合;REG_NOMATCH 代表模式未符合。其他回傳值則表示執行錯誤,可使用 regerror() 產生診斷訊息。若需要子比對位置,請提供 regmatch_t 項目的陣列及其容量;第一個項目描述整體比對結果。使用 REG_NOSUB 時,不要要求子比對位置。

這個完整範例會編譯一個模式、測試兩個字串,並釋放編譯後的物件。範例會透過 regerror() 回報編譯與執行診斷。依據提供的成功執行結果,它先輸出 match,再輸出 no match,並以代碼 0 結束。範例中的輸出標籤維持英文,因為程式碼與輸出區塊必須與原文逐位元組相同。

執行此範例:

本節中的程式碼以及顯示的標籤或輸出仍為英文。

#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> 實作;輸出標籤維持英文,程式碼與輸出區塊均未翻譯。