如何在C語言中使用正規表示式

2021-06-02 01:25:50 字數 2873 閱讀 3149

如果使用者熟悉linux下的sed、awk、grep或vi,那麼對正規表示式這一概念肯定不會陌生。由於它可以極大地簡化處理字串時的複雜度,因此現在已經在許多linux實用工具中得到了應用。千萬不要以為正規表示式只是perl、python、bash等指令碼語言的專利,作為c語言程式設計師,使用者同樣可以在自己的程式中運用正規表示式。 

標準的c和c++都不支援正規表示式,但有一些函式庫可以輔助c/c++程式設計師完成這一功能,其中最著名的當數philip hazel的perl-compatible regular expression庫,許多linux發行版本都帶有這個函式庫。 

下面簡單介紹一下linux自帶的regex,一種用c語言開發的正規表示式;

為了提高效率,在將乙個字串與正規表示式進行比較之前,首先要用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()函式成功返回時,pmatch[0]中儲存了整個匹配的結果,即使string中有多處匹配的話,pmatch只匹配第乙個就結束了。如果在正規表示式regex(regcomp中的第二個引數)有小括號的形式出現並且匹配成功的話,則小括號內在string中匹配的內容會被記錄在pmatch中,下標從1開始。如果匹配成功,regmatch_t結構中會記錄相應的位置資訊,否則regmatch_t的rm_so和rm_eo為-1;

無論什麼時候,當不再需要已經編譯過的正規表示式時,都應該呼叫函式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* substra(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語言中使用正規表示式

有四個函式 int regcomp regex t compiled,const char pattern,int cflags 引數1 結構體 編譯 字串 結構體 儲存正規表示式 引數2 正規表示式串。引數3 標誌位 1.擴充套件正則 reg extended 2.忽略大小寫 reg icase ...

如何在C語言中巧用正規表示式

如何在c語言中巧用正規表示式 如果使用者熟悉 linux 下的sed awk grep或vi 那麼對正規表示式這一概念肯定不會陌生。由於它可以極大地簡化處理字串時的複雜度,因此現在已經在許多 linux 實用工具中得到了應用。千萬不要以為正規表示式只是 perl python bash 等指令碼語言...

如何在C語言中巧用正規表示式

如果使用者熟悉linux下的sed awk grep或vi,那麼對正規表示式這一概念肯定不會陌生。由於它可以極大地簡化處理字串時的複雜度,因此現在已經在許多linux實用工具中得到了應用。千萬不要以為正規表示式只是perl python bash等指令碼語言的專利,作為c語言程式設計師,使用者同樣可...