專案架構:POSIX Regex API
<regex.h>:標準 C 正則庫(POSIX.2),支援擴展正則語法(ERE)
- 核心函數:
regcomp 編譯、regexec 匹配、regfree 釋放
- 匹配結果:
regmatch_t 陣列記錄捕獲組起止位置 rm_so/rm_eo
電話號碼提取:中國大陸通用規則
正則模式設計
// 擴展正則語法(ERE)
(([0-9]{11})|((400|800)([0-9\\-]{7,10})|(([0-9]{4}|[0-9]{3})(-| )?)?([0-9]{7,8})((-| |轉)*([0-9]{1,4}))?))
涵蓋類型
| 類型 | 模式片段 | 範例 |
| 手機號 | [0-9]{11} | 13812345678 |
| 400/800 號 | (400|800)([0-9\\-]{7,10}) | 400-800-1234、8001234567 |
| 固話(含區號、分機) | (([0-9]{4}|[0-9]{3})(-| )?)?([0-9]{7,8})((-| |轉)*([0-9]{1,4}))? | 010-12345678、021 87654321 轉 801 |
日期時間提取:中文格式標準化
兩階段匹配策略
- 日期:
[0-9]{2,4}(-|/|年)[0-9]{1,2}(-|/|月)[0-9]{1,2}
- 時間:
[0-9]{1,2}:[0-9]{1,2}(:[0-9]{1,2})?
解析邏輯:分隔符自適應 + 統一格式化輸出
- 檢測分隔符:
-、/、年/月
- 提取年/月/日,兩位數年份自動補
2000+
- 提取時/分/秒,秒可選預設 0
- 統一輸出:
YYYY-MM-DD HH:MM:SS
核心工具函數
// 子串提取:[pos, pos+len)
char* substr(const char* str, int pos, int len) {
char* sp = malloc(len + 1);
for (int i = 0; i < len; ++i) sp[i] = str[pos + i];
sp[len] = '\0';
return sp;
}
// 正向查找子串位置
int find(const char* src, const char* target) { /* 朴素 O(nm) 實現 */ }
// 反向查找子串位置
int rfind(const char* src, const char* target) { /* 從右向左 */ }
完整 API 介面
// phone_extract.h
int phone_extract(const char* str, char** phone); // 返回 0 成功,*phone 需 free()
int datetime_extract(const char* str, char** datetime); // 返回 0 成功,格式 YYYY-MM-DD HH:MM:SS
使用範例
#include "PhoneDateExtract.h"
#include <stdio.h>
#include <stdlib.h>
int main() {
char* phone = NULL;
phone_extract("電話:800-2142-325", &phone);
printf("phone = [%s]\n", phone); // [800-2142-325]
free(phone);
char* dt = NULL;
datetime_extract("2011年3月7日 14:03", &dt);
printf("datetime = [%s]\n", dt); // [2011-03-07 14:03:00]
free(dt);
return 0;
}
編譯與鏈接
gcc test.c PhoneDateExtract.c -o test -lregex
# 某些系統需顯式鏈接 -lregex
關鍵技術點與避坑指南
- ERE vs BRE:
regcomp(..., REG_EXTENDED) 啟用擴展正則(支援 {m,n}、|、() 等),否則為基本正則(需轉義)。
- 記憶體管理:
regmatch_t 給出位置,必須手動 substr 複製並 free;輸出緩衝區同樣需調用方 free。
- 匹配貪婪性:POSIX 正則預設貪婪(最長匹配),
[0-9]* 會吃盡可能多數字。
- 中文字元處理:正則按位元組匹配,UTF-8 下
年 佔 3 字節,模式中直接寫 年 需原始碼編碼一致,或用十六進制 \\xE5\\xB9\\xB4。
- 效能考量:頻繁調用請緩存
regex_t 編譯結果,避免重複 regcomp。
- 錯誤處理:
regcomp/regexec 非零返回碼需用 regerror 獲取錯誤訊息。
擴展方向
- 支援更多電話格式:國際碼
+86、括號區號 (010)
- 日期支援相對時間:
今天、明天、下週一
- 引入 PCRE2 庫:支援 Perl 相容正則(非貪婪
.*?、前瞻/後顧、遞歸),功能更強
- 封裝為 C++ 類:RAII 管理
regex_t,提供流式介面