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

C 語言正則表達式實戰:電話號碼與日期時間提取完整方案

     編輯:關於C

使用 POSIX 正則庫 regex.h 實作中國大陸電話號碼(手機、固話、400/800)與中文日期時間的提取與標準化。本文提供完整模組化代碼(頭文件、實作、測試),涵蓋正則模式設計、匹配提取、子串解析、格式化輸出全流程。

一、電話號碼提取:支援三大類型

正則模式解析


// 完整模式(延伸可讀性版)
(
    ([0-9]{11})                                    // 11 位手機號
  | (                                              // 或:固話/400/800
        (400|800)([0-9\-]{7,10})                   // 400/800 開頭
      | (([0-9]{3,4})([- ])?)?([0-9]{7,8})         // 區號(3-4碼)+分隔符?+號碼(7-8碼)
        (([- ]|转)*([0-9]{1,4}))?                  // 分機號
    )
)

核心函數:phone_extract


int phone_extract(const char* str, char** phone) {
    const char* pattern = "(([0-9]{11})|((400|800)([0-9\\-]{7,10})|(([0-9]{4}|[0-9]{3})(-| )?)?([0-9]{7,8})((-| |转)*([0-9]{1,4}))?))";
    regex_t reg; regmatch_t pm[1];
    regcomp(®, pattern, REG_EXTENDED);
    int z = regexec(®, str, 1, pm, 0);
    regfree(®);
    if (z != 0) { *phone = NULL; return -1; }

    // 提取匹配子串
    char* matched = substr(str, pm[0].rm_so, pm[0].rm_eo - pm[0].rm_so);
    *phone = strdup(matched);
    free(matched);
    return 0;
}

二、日期時間提取:中文/數字混合格式

分離式正則:日期 + 時間


// 日期:2011年3月7日 / 2011-03-07 / 2011/03/07
const char* pattern_date = "[0-9]{2,4}(-|/|年)[0-9]{1,2}(-|/|月)[0-9]{1,2}";
// 時間:14:03 / 14:03:59
const char* pattern_time = "[0-9]{1,2}:[0-9]{1,2}(:[0-9]{1,2})?";

核心函數:datetime_extract


int datetime_extract(const char* str, char** datetime) {
    char* out = (char*)malloc(20); // "YYYY-MM-DD HH:MM:SS\0"
    *datetime = out;
    int Y=0, M=0, D=0, h=0, m=0, s=0;

    // 1. 提取日期部分
    regex_t reg; regmatch_t pm[1];
    regcomp(®, pattern_date, REG_EXTENDED);
    if (regexec(®, str, 1, pm, 0) == 0) {
        char* dstr = substr(str, pm[0].rm_so, pm[0].rm_eo - pm[0].rm_so);
        // 解析年月日:尋找分隔符位置
        int sep1 = find(dstr, "-"); if (sep1<0) sep1 = find(dstr, "/"); if (sep1<0) sep1 = find(dstr, "年");
        int sep2 = rfind(dstr, "-"); if (sep2<0) sep2 = rfind(dstr, "/"); if (sep2<0) sep2 = find(dstr, "月");
        int off = (sep1>=0 && strstr(dstr+sep1, "年")) ? 2 : 1; // "年"/"月" 佔 2 字節 (GBK) 或 3 (UTF-8) - 此處假設 GBK

        Y = atoi(substr(dstr, 0, sep1));
        M = atoi(substr(dstr, sep1+off, sep2-sep1-off));
        D = atoi(substr(dstr, sep2+off, strlen(dstr)-sep2-off));
        if (Y < 100) Y += 2000;
        free(dstr);
    }
    regfree(®);

    // 2. 提取時間部分
    regcomp(®, pattern_time, REG_EXTENDED);
    if (regexec(®, str, 1, pm, 0) == 0) {
        char* tstr = substr(str, pm[0].rm_so, pm[0].rm_eo - pm[0].rm_so);
        int c1 = find(tstr, ":");
        int c2 = rfind(tstr, ":");
        h = atoi(substr(tstr, 0, c1));
        if (c1 != c2) {
            m = atoi(substr(tstr, c1+1, c2-c1-1));
            s = atoi(substr(tstr, c2+1, strlen(tstr)-c2-1));
        } else {
            m = atoi(substr(tstr, c1+1, strlen(tstr)-c1-1));
            s = 0;
        }
        free(tstr);
    }
    regfree(®);

    sprintf(out, "%04d-%02d-%02d %02d:%02d:%02d", Y, M, D, h, m, s);
    return 0;
}

三、輔助工具函數

  • substr(str, pos, len):安全子串提取(分配新記憶體)
  • find(src, sub) / rfind(src, sub):正向/反向查找子串位置

四、編譯與測試


# 編譯
gcc test.c PhoneDateExtract.c -o test -lregex

# 測試輸出
format phone = [800-2142-325]
format datetime = [2011-03-07 14:03:00]

五、工程化建議

  1. 編碼一致性:正則與字串處理需統一編碼(UTF-8 推薦),中文分隔符「年/月」在 UTF-8 佔 3 字節,off 需動態計算
  2. 正則效能:regcomp 開銷大,高頻調用場景應預編譯快取 regex_t
  3. 邊界測試:測試無匹配、多匹配、邊界長度、異常分隔符等案例
  4. 替代方案:C++11 <regex>、PCRE2、RE2 提供更豐富語法與更好效能

此模組已在實際項目中穩定運行,可直接整合至日誌分析、爬蟲清洗、表單驗證等管線。

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