如果使用者熟悉
linux
下的sed
、awk
、grep或vi
,那麼對正規表示式這一概念肯定不會陌生。由於它可以極大地簡化處理字串時的複雜度,因此現在已經在許多
linux
實用工具中得到了應用。千萬不要以為正規表示式只是
perl
、python
、bash
等指令碼語言的專利,作為
c語言程式設計師,使用者同樣可以在自己的程式中運用正規表示式。
標準的c和
c++都不支援正規表示式,但有一些函式庫可以輔助
c/c++
程式設計師完成這一功能,其中最著名的當數
philip hazel
的perl-compatible regular expression
庫,許多
linux
發行版本都帶有這個函式庫。
編譯正規表示式
為了提高效率,在將乙個字串與正規表示式進行比較之前,首先要用
regcomp()
函式對它進行編譯,將其轉化為
regex_t
結構:int regcomp(regex_t *preg, const char *regex, int cflags); 引數
regex
是乙個字串,它代表將要被編譯的正規表示式;引數
preg
指向乙個宣告為
regex_t
的資料結構,用來儲存編譯結果;引數
cflags
決定了正規表示式該如何被處理的細節。
如果函式
regcomp()
執行成功,並且編譯結果被正確填充到
preg
中後,函式將返回
0,任何其它的返回結果都代表有某種錯誤產生。
匹配正規表示式
一旦用regcomp()
函式成功地編譯了正規表示式,接下來就可以呼叫
regexec()
函式完成模式匹配:
int regexec(const regex_t *preg, const char *string, size_t nmatch,regmatch_t pmatch, int eflags);
typedef struct regmatch_t; 引數
preg
指向編譯後的正規表示式,引數
string
是將要進行匹配的字串,而引數
nmatch
和pmatch
則用於把匹配結果返回給呼叫程式,最後乙個引數
eflags
決定了匹配的細節。
在呼叫函式
regexec()
進行模式匹配的過程中,可能在字串
string
中會有多處與給定的正規表示式相匹配,引數
pmatch
就是用來儲存這些匹配位置的,而引數
nmatch
則告訴函式
regexec()
最多可以把多少個匹配結果填充到
pmatch
陣列中。當
regexec()
函式成功返回時,從
string+pmatch[0].rm_so
到string+pmatch[0].rm_eo
是第乙個匹配的字串,而從
string+pmatch[1].rm_so
到string+pmatch[1].rm_eo
,則是第二個匹配的字串,依此類推。
釋放正規表示式
無論什麼時候,當不再需要已經編譯過的正規表示式時,都應該呼叫函式
regfree()
將其釋放,以免產生記憶體洩漏。
void regfree(regex_t *preg); 函式
regfree()
不會返回任何結果,它僅接收乙個指向
regex_t
資料型別的指標,這是之前呼叫
regcomp()
函式所得到的編譯結果。
如果在程式中針對同乙個
regex_t
結構呼叫了多次
regcomp()
函式,posix
標準並沒有規定是否每次都必須呼叫
regfree()
函式進行釋放,但建議每次呼叫
regcomp()
函式對正規表示式進行編譯後都呼叫一次
regfree()
函式,以盡早釋放占用的儲存空間。
報告錯誤資訊
如果呼叫函式
regcomp()
或regexec()
得到的是乙個非
0的返回值,則表明在對正規表示式的處理過程中出現了某種錯誤,此時可以通過呼叫函式
regerror()
得到詳細的錯誤資訊。
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
緩衝區中填入格式化後的錯誤資訊,同時返回錯誤資訊的長度。
應用正規表示式
最後給出乙個具體的例項,介紹如何在
c語言程式中處理正規表示式。
#include
#include
#include
/* 取子串的函式
*/ static char* substr(const char*str, unsigned start, unsigned end)
/* 主程式*/
int main(int argc, char** argv)
/* 逐行處理輸入的資料
*/ while(fgets(lbuf, sizeof(lbuf), stdin))
/* 輸出處理結果
*/ for (x = 0; x < nmatch && pm[x].rm_so != -1; ++ x)
} /*
釋放正規表示式
*/ regfree(®);
return 0; }
上述程式負責從命令列獲取正規表示式,然後將其運用於從標準輸入得到的每行資料,並列印出匹配結果。執行下面的命令可以編譯並執行該程式:
# gcc regexp.c -o regexp
# ./regexp 'regex[a-z]*' < regexp.c
0003: #include
$0='regex'
0027: regex_t reg;
$0='regex'
0054: z = regexec(®, lbuf, nmatch, pm, 0);
$0='regexec'
小結
對那些需要進行複雜資料處理的程式來說,正規表示式無疑是乙個非常有用的工具。本文重點在於闡述如何在
c語言中利用正規表示式來簡化字串處理,以便在資料處理方面能夠獲得與
perl
語言類似的靈活性。
如何在C語言中巧用正規表示式
如何在c語言中巧用正規表示式 如果使用者熟悉 linux 下的sed awk grep或vi 那麼對正規表示式這一概念肯定不會陌生。由於它可以極大地簡化處理字串時的複雜度,因此現在已經在許多 linux 實用工具中得到了應用。千萬不要以為正規表示式只是 perl python bash 等指令碼語言...
如何在C語言中巧用正規表示式
如果使用者熟悉linux下的sed awk grep或vi,那麼對正規表示式這一概念肯定不會陌生。由於它可以極大地簡化處理字串時的複雜度,因此現在已經在許多linux實用工具中得到了應用。千萬不要以為正規表示式只是perl python bash等指令碼語言的專利,作為c語言程式設計師,使用者同樣可...
如何在C語言中巧用正規表示式
如果使用者熟悉linux下的sed awk grep或vi,那麼對正規表示式這一概念肯定不會陌生。由於它可以極大地簡化處理字串時的複雜度,因此現在已經在許多linux實用工具中得到了應用。千萬不要以為正規表示式只是perl python bash等指令碼語言的專利,作為c語言程式設計師,使用者同樣可...