首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

GNU Regex 正則表達式在 C 語言中的應用:regex.h 完整實戰指南

     編輯:關於C語言

GNU Regex 正則表達式在 C 語言中的應用:regex.h 完整實戰指南

POSIX 正則表達式 API (regex.h) 是 C 語言處理複雜字串匹配、擷取、替換的標準工具。本文從基礎語法到完整編譯執行範例,詳細說明 regcomp、regexec、regmatch_t 結構體使用、捕獲群組擷取、錯誤處理與常見陷阱,並提供可直接編譯的完整程式碼。

POSIX 正則基礎語法速查

元字符說明範例
.任意單一字符(除換行)a.c 匹配 abc, axc
[]字符集合[aeiou] 匹配任一母音
[^]排除字符集合[^0-9] 匹配非數字
-範圍[a-zA-Z0-9] 字母數字
\w單詞字符 [a-zA-Z0-9_]
\d數字 [0-9]
\s空白字符
{m,n}量詞:m 到 n 次\d{3,5} 3-5 位數字
()捕獲群組(\w+)=(\w+) 鍵值對
|或cat|dog
^ $行首/行尾

核心 API 流程

// 1. 編譯正則
regex_t regex;
int ret = regcomp(&regex, pattern, REG_EXTENDED | REG_NEWLINE);
if (ret != 0) {
    char errbuf[1024];
    regerror(ret, &regex, errbuf, sizeof(errbuf));
    fprintf(stderr, "Regex compile failed: %s\n", errbuf);
    return -1;
}

// 2. 執行匹配
regmatch_t matches[10];  // matches[0] 為整體匹配,[1]... 為捕獲群組
ret = regexec(&regex, string, 10, matches, 0);
if (ret == REG_NOMATCH) { /* 無匹配 */ }
else if (ret != 0) { /* 執行錯誤 */ }

// 3. 擷取捕獲群組
for (int i = 0; i < 10; i++) {
    if (matches[i].rm_so == -1) break;  // 無匹配
    int start = matches[i].rm_so;
    int end = matches[i].rm_eo;
    int len = end - start;
    char buf[256];
    strncpy(buf, string + start, len);
    buf[len] = '\0';
    printf("Group %d: %s\n", i, buf);
}

// 4. 釋放資源
regfree(&regex);

完整可編譯範例:鍵值對擷取

#include <stdio.h>
#include <sys/types.h>
#include <regex.h>
#include <string.h>

int main() {
    const char *p_str = " Url = www.google.com.hk ;";
    const char *p_reg = "[[:space:]]*([^[:space:]]+)[[:space:]]*=[[:space:]]*([^[:space:]]+)[[:space:]]*;";

    regex_t reg;
    regmatch_t matchs[10];
    int r, i;

    // 編譯:REG_EXTENDED 啟用擴展正則(支援 + ? {m,n} 等)
    r = regcomp(&reg, p_reg, REG_EXTENDED);
    if (r != 0) {
        char err[256];
        regerror(r, &reg, err, sizeof(err));
        printf("Compile error: %s\n", err);
        return 1;
    }

    // 執行匹配
    r = regexec(&reg, p_str, 10, matchs, 0);
    if (r != 0) {
        if (r == REG_NOMATCH) printf("No match\n");
        else {
            char err[256];
            regerror(r, &reg, err, sizeof(err));
            printf("Exec error: %s\n", err);
        }
        regfree(&reg);
        return 1;
    }

    // 輸出所有捕獲群組
    for (i = 0; i < 10; i++) {
        int start = matchs[i].rm_so;
        int end = matchs[i].rm_eo;
        if (start == -1) break;
        int len = end - start;
        char buf[256];
        strncpy(buf, p_str + start, len);
        buf[len] = '\0';
        printf("match[%d]: %s\n", i, buf);
    }

    regfree(&reg);
    return 0;
}

執行結果

match[0]:  Url = www.google.com.hk ;
match[1]: Url
match[2]: www.google.com.hk

關鍵細節與避坑指南

  1. REG_EXTENDED 必須啟用:否則 {m,n}、+、?、| 等擴展語法無效,僅支援基本正則(BRE)。
  2. matches[0] 是整體匹配:捕獲群組從 matches[1] 開始。
  3. rm_so == -1 表示該群組未參與匹配:需檢查後再存取。
  4. C 字串轉義地獄:正則中的 \ 在 C 字串需寫成 \\。建議使用原始字串字面量(C23)或外部配置檔讀取。
  5. 效能考量:regcomp 開銷大,相同正則重複使用時應快取編譯後的 regex_t。
  6. 執行緒安全:regex_t 非執行緒安全,多執行緒需各自編譯或加鎖。
  7. 替換功能:POSIX regex 無內建替換,需自行結合 regexec 位置資訊實現。

替代方案比較

庫優點缺點適用場景
POSIX regex.h標準、無依賴、Unicode 支援(當前 locale)API 繁瑣、無替換、效能中等標準 C 專案、嵌入式系統
PCRE / PCRE2Perl 相容、功能豐富、JIT 加速外部依賴、授權 (BSD)複雜文本處理、高效能需求
RE2 (Google)線性時間保證、安全、C++11C API 需包裝、功能受限非信任輸入、高併發服務
SLRE / TinyRegex極輕量、單檔案、嵌入式友善功能子集、無 {m,n} 貪婪模式微控制器、極度受限環境

掌握 regex.h 讓你在無法引入重型依賴的環境中,依然能優雅地解決複雜字串解析問題。建議結合 man 3 regex、man 7 regex 閱讀完整手冊,並實作一個通用的「正則擷取工具函數」加入個人工具箱。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved