regex.h (Linux 原生, Windows 再說)
Regex.h 實作主要分 3 階段,regcom, regexec, regfree。 // 要被批配的 buffer 跟一些參數
int status, len, i;
char buf[1024], data[1024];
getdata(data);
// 正規表示式的會要先 compile (regcomp())並儲存在 regex_t 此資料結構
regex_t preg;
// 設定批配模式的 flag.
// REG_EXTENDED ERE (Extended Regular Expression, 不用就是 BRE)
// REG_ICASE 忽略大小寫
// REG_NOSUB 不儲存批配後的結果
// REG_NEWLINE 識別換行符(^$ 這類符號會成每一行的開頭跟結尾), REG_NEWLINE 效力 > eflags
int cflags = REG_EXTENDED | REG_NEWLINE;
// 正規表示式的批配樣板
const char * regex = "Name: ([A-Z a-z]+)\nYear of Birth: ([^\n]*)\n([^:]*: [^\n]*)";
// pmatch 為 struct 陣列去儲存批配後的結果
// pmatch.rm_so 批配到的子字串在 target string 的起始 index
// pmatch.rm_eo 批配到的子字串在 target string 的終止 index
// nmatch 為宣告 pmatch 的陣列大小
const size_t nmatch = 10;
regmatch_t pmatch[nmatch];
// eflags 也會對批配做改動
// REG_NOTBOL 開頭批配符號(^)永遠批配不到
// REG_NOTEOL 結尾批配符號($)永遠批配不到
// REG_STARTEND 是直接使用 pmatch[0] 的 rm_so 跟 rm_eo
// 作為字串頭尾的 index 然後批配,是為了避免 target string
// 中間有終止符(\0) 或 字串太長 strlen() 會 fail.
int eflags = 0;
// compile regex
if( regcomp(&preg, regex, cflags) != 0 ) {
puts("regex compile error!\n");
return;
}
// 進行批配 status = 0 代表成功
status = regexec(&preg, data, nmatch, pmatch, eflags);
if (status == REG_NOMATCH) {
printf("No Match\n");
} else if (status == 0) {
// pmatch[0] 所指的子字串會是整串
// pmatch[1], pmatch[2]... 會是括弧裡 sub regex,通常拿來取真正想要的值
for (i = 0; i < nmatch && pmatch[i].rm_so >= 0; ++i) {
len = pmatch[i].rm_eo - pmatch[i].rm_so;
strncpy(buf, data + pmatch[i].rm_so, len);
buf[len] = '\0';
printf("match %d :\n%s\n\n", i+1, buf);
}
}
regfree(&preg);
return;
測試資料 跟 結果
測試資料Name: JunYe Year of Birth: 1993 Gender: Male結果
match 1 : Name: JunYe Year of Birth: 1993 Gender: Male match 2 : JunYe match 3 : 1993 match 4 : Gender: Male
Basic (BRE) and extended (ERE) regular expression
在一些特殊字元處理不一樣, 請參考 GNU的說明參考資料 :