在很多人看來,正規表達式看上去古怪且複雜,是以往往不想去觸及或使用。如果我們抛開這種“畏難”心理,在經過循序漸進地學習之後,就會發現這些複雜的表達式其實寫起來還是相當簡單的。一旦它被你所“馴服”,就可利用正規表達式把原需數小時辛苦且易錯的文本處理工作壓縮在幾分鐘(甚至幾秒鐘)内完成。
正規表達式定義
正規表達式(regular expression)是Linux系統中一種非常重要的字元串搜尋模式,是一組規則字元的集合。這些規則字元能夠組成我們所需要的搜尋規則,效率高、功能強,可以極大地簡化處理字元串時的複雜度。在很多Linux工具(sed、grep、find等)和腳本語言(awk、perl等)中都有着重要的地位。當我們在編寫字元串相關的應用程式時,掌握正規表達式會起到事半功倍的效果。
C中的正規表達式
标準C和C++都不支援正規表達式,但是千萬不要以為正規表達式就隻是Perl、Python、Bash等腳本語言的專利,作為C語言程式員,使用者同樣可以在自己的程式中運用正規表達式,隻是需要一些函數庫輔助C/C++程式員來完成這一功能。許多Linux發行版本都帶有POSIX函數庫,下面我将以POSIX函數庫中的Regex系列函數來說明在Linux c下如何使用正規表達式。
首先要用Regcomp()函數對它進行編譯,将其轉化為Regex_t結構。因為一個正規表達式需要編譯成一個特定的資料結構才能被後續的函數使用。Regcomp()函數的原型是:
int Regcomp(regex_t *preg, const char *regex, int cflags)
參數preg指向一個聲明為regex_t的資料結構,用來儲存編譯結果。參數regex為要編譯的正規表達式字元串。參數cflags是編譯開關,編譯開關可以控制規則生成的特性,如REG_EXTEND代表使用擴充正規表達式模式;REG_ICASE表示對規則中字元串不區分大小寫;REG_NOSUB隻檢查是否有符合規則的子串。
下面比對正規表達式,一旦用Regcomp()函數成功地編譯了正規表達式,接下來就可調用regexec()函數完成模式比對。Regexec()函數的原型:
int regexec(const regex_t *preg, const char *string, size_t nmatch,regmatch_t pmatch[], int eflags)
函數用于在字元串(參數string)中比對正規表達式(參數preg)。而參數nmatch和pmatch則用于把比對結果傳回給調用程式。在調用函數egexec()進行模式比對的過程中,可能在字元串string中會有多處與給定的正規表達式相比對。參數pmatch用來儲存這些比對位置。參數nmatch則告訴函數regexec()最多可以把多少個比對結果填充到pmatch數組中。
typedef struct {
regoff_t rm_so;
regoff_t rm_eo;
} regmatch_t;
其中rm_so表示滿足規則的子串在string中的起始偏移量,rm_eo表示滿足規則的子串在string中的後續偏移量。當regexec成功傳回時,從pmatch[0].rm_so到pmatch[0].rm_eo是第一個比對的字元串。最後一個參數eflags決定了比對的特性,當需要比對的string非常大的時候可以通過eflags來表示是否是第一行(REG_NOTBOL),或最後一行(REG_NOTEOL)。
還有一個函數是用來擷取錯誤資訊的,size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)。參數errcode是來自函數Regcomp()或regexec()的錯誤代碼,而參數preg則是由函數Regcomp()得到的編譯結果,其目的是把格式化消息所必須的上下文提供給regerror()函數。在執行函數regerror()時,将按照參數errbuf_size指明的最大位元組數。在errbuf緩沖區中填入格式化後的錯誤資訊,同時傳回錯誤資訊的長度。
最後釋放正規表達式。無論什麼時候,當不再需要已經編譯過的正規表達式時,都應該調用函數regfree()将其釋放,以免産生記憶體洩漏。void regfree(regex_t *preg); 函數regfree()不會傳回任何結果,它僅接收一個指向regex_t資料類型的指針,這是之前調用Regcomp()函數所得到的編譯結果。
執行個體說明
下面介紹如何在Linux C中正确使用正規表達式,以查找有關字元串并列印出來為例:
#include <stdio.h>
#include <sys/types.h>
#include <regez.h>
in chk_line(int lineno, regex_t *reg,char *line)
{
int rtn,i,len;
regmatch_t pmatch;
char *url,*pbuf;
fprintf(stderr,"%4d",lineno);
rtn = regexec(reg,line,1,&pmatch,0);
pbuf = line;
while(rtn == 0)
len = pmatch.rm_eo - pmatch.rm_so;
url = (char*)malloc((len+1)*sizeof(char));
memset(url,0,(len+1)*sizeof(char));
memcpy(url,&pbuf[pmatch.rm_so].len);
fprintf(stderr,"%s",url);
free(url);
pbuf += pmatch.rm_eo;
rtn = regexec(reg,pbuf,1,&pmatch,REG_NOTBOL);
}
fprintf(stderr,"/n");
return 0;
int chk_file(const char *filename)
FILE *fp;
char *pattern = "^(hisencyber)(.com|.com.cn)";
char buf[1024],line[1024];
int rtn,lineno,flag;
fp = fopen(filename,"r");
if(fp == NULL)
fprintf(stderr,"OPen file failed/n",filename);
return -1;
rtn = Regcomp(®,patten,REG_ICASE|REG_EXTENDED);
if(rtn)
fprintf(stderr,"compile failed./n");
fclose(fp);
lineno = 1;
memset(line,0,sizeof(line));
while(fgets(line,sizeof(line),fp)!= NULL)
chk_line(lineno++,®,line);
regefree(®);
int main (int argc,char *argv[])
int rtn;
if(argc != 2)
fprintf(stderr,"Usage:chkfileurl <file> /n ");
return 1;
rtn = chk_file(argv[1]);
return rtn;
正規表達式示例表
字 符 意 義 示 例
* 任意長度的字元串。 a* 表示: 空字元串、aaaa、a…
? 長度為0或者1的字元串。 a? 表示: 空字元串和a。
+ 長度為一個或者多個的字元串。 a+表示:a、aa、aaaaaa…
. 任意字元。 a. 表示:a後跟任意字元。
{} 代表上一規則重複數目、
{1,1,s}包含一組比對花括号,裡面有兩個數字和一個字元,表示在指定次數範圍内找到字元。 a{3}表示:三個a、
a{1,3}表示:一個到三個a、
a{3,} 表示:大于等于三個a、
{3,7,a}表示在3到7次重複範圍内比對字元a。
[] 集合,代表方括号中任意一個字元。 [ab] 表示:a或者b都可以、
[a-z] 表示:從a到z的字元。
() 組,代表一組字元。 (ab){2}表示:abab。
a/b 同時滿足。 a/b表示:字元串a後跟字元串b才能滿足要求。
a|b 并列,代表符合a或者符合b都可以 a|b表示: 字元串a或者字元串b都滿足要求。
^ 如果放在開頭表示代表該規則必須在字元串的開頭,其他位置代表字元本身。
如果放在[]中的開頭表示對該集合取反,其他位置代表字元本身。 ^a表示:a必須在字元串的開頭、
[^a]表示:除了a以外的其他字元。
$ 如果放在最後表示該規則必須放在最後,其他位置代表字元本身。 a$表示:a必須在字元串最後。
/:s 正規表達式用 /:s 表示空格。 a/:sb 比對 a b。
/:a 正規表達式用 /:a 表示字元與數字。 a/:a 比對 ab、a6 等。
/:c 正規表達式用 /:c 僅表示字元。 a/:c 比對 ac等,不比對a1等。
/:p 正規表達式用 /:p 表示可列印字元。
/:D 正規表達式用 /:d 僅表示數字。 a/:c 比對 a1等,不比對ac等。
/:x00 正規表達式用 /:x00 表示ASCII字元。
/:r 正規表達式用 /:r 表示回車。
/:N 正規表達式用 /:d 表示換行。
本文重點在于闡述如何在Linux C中利用正規表達式來台灣字元串處理,另外Linux中正規表達式内部定義了諸多内部規則來友善開發人員使用,具體含義可以檢視 man regex,相信熟悉它對你的工作會有非常大的幫助!