在linux下,如何在C語言中使用正則表示式(整理)
阿新 • • 發佈:2018-12-22
一個正則表示式的教程可以參看(裡面有個測試正則表示式的工具)
正則表達是用來匹配字串的好東東。
如果使用者熟悉Linux下的sed、awk、grep或vi,那麼對正則表示式這一概念肯定不會陌生。由於它可以極大地簡化處理字串時的複雜度,因此現 在已經在許多Linux實用工具中得到了應用。千萬不要以為正則表示式只是Perl、Python、Bash等指令碼語言的專利,作為C語言程式設計師,使用者同 樣可以在自己的程式中運用正則表示式。
標準的C和C++都不支援正則表示式,但有一些函式庫可以輔助C/C++程式設計師完成這一功能,其中最著名的當數Philip Hazel的Perl-Compatible Regular Expression庫,許多Linux發行版本都帶有這個函式庫。
本人使用的是fedora 8系統,該版本中就帶有這個函式庫,下面介紹一下如何使用。(實際上只要使用man命令查詢就可瞭解很多有關的細節了)
很多在網上都有介紹,但多有些小的錯誤,於是我更改了並整理了一下。
要使用正則表示式的函式庫在你的程式前面包含
#include <sys/types.h>
#include <regex.h>
下面介紹下如何使用:
首先,編譯正則表示式。
為了提高效率,在將一個字串與正則表示式進行比較之前,首先要用regcomp()函式對它進行編譯,將其轉化為regex_t結構:
int regcomp(regex_t *preg, const char *regex,int cflags);
引數regex是一個字串,它代表將要被編譯的正則表示式;引數preg指向一個宣告為regex_t的資料結構,用來儲存編譯結果;引數cflags決定了正則表示式該如何被處理的細節。 (此處可以用man regcomp 命令檢視詳細的解釋)
如果函式regcomp()執行成功,並且編譯結果被正確填充到preg中後,函式將返回0,任何其它的返回結果都代表有某種錯誤產生。
接下來匹配正則表示式。
一旦用regcomp()成功地編譯了正則表示式,接下來就可以呼叫regexec()完成模式匹配:
int regexec(const regex_t *preg, const char *string, size_t nmatch,regmatch_t pmatch[], int eflags);
typedef struct
{
regoff_t rm_so;
regoff_t rm_eo;
} 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);
報告錯誤資訊
如果呼叫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緩衝區中填入格式化後的錯誤資訊,同時返回錯誤資訊的長度。
給出一個應用正則表示式的例子
(這個例子網上容易找到,但多半有些小錯誤,不能編譯成功,我將其修改寫在了下面)
例子如下:
#include <stdio.h>
#include <sys/types.h>
#include <regex.h>
/* 取子串的函式 */
static char* substr(const char*str,unsigned start, unsigned end)
{
unsigned n = end - start;
static char stbuf[256];
strncpy(stbuf, str + start, n);
stbuf[n] = 0;
return stbuf;
}
int main(int argc, char** argv)
{
char * pattern;
int x, z, lno = 0, cflags = 0;
char ebuf[128], lbuf[256];
regex_t reg;
regmatch_t pm[10];
const size_t nmatch = 10;
/* 編譯正則表示式*/
pattern = argv[1];
z = regcomp(®, pattern, cflags);
if (z != 0)
{
regerror(z, ®, ebuf, sizeof(ebuf));
fprintf(stderr, "%s: pattern '%s' /n",ebuf, pattern);
return 1;
}
/* 逐行處理輸入的資料 */
while(fgets(lbuf, sizeof(lbuf), stdin))
{
++lno;
if ((z = strlen(lbuf)) > 0 && lbuf[z-1]== '/n') lbuf[z - 1] = 0;
/* 對每一行應用正則表示式進行匹配 */
z = regexec(®, lbuf, nmatch, pm, 0);
if (z == REG_NOMATCH) continue;
else if (z != 0)
{
regerror(z, ®, ebuf, sizeof(ebuf));
fprintf(stderr, "%s: regcom('%s')/n",
ebuf, lbuf);
return 2;
}
/* 輸出處理結果 */
for (x = 0; x < nmatch && pm[x].rm_so != -1; ++ x)
{
if (!x) printf("%04d: %s/n", lno, lbuf);
printf(" $%d='%s'/n", x, substr(lbuf, pm[x].rm_so,pm[x].rm_eo));
}
}
/* 釋放正則表示式 */
regfree(®);
return 0;
}
上述程式負責從命令列獲取正則表示式,然後將其運用於從標準輸入得到的每行資料,並打印出匹配結果。執行下面的命令可以編譯並執行該程式:
# gcc regexp.c -o regexp (編譯是會有兩個警告,沒有事)
# ./regexp 'regex[a-z]*' < regexp.c
0003: #include <regex.h>
$0='regex'
0027: regex_t reg;
$0='regex'
0054: z = regexec(?, lbuf, nmatch, pm, 0);
$0='regexec'
小結
在C語言中使用正則表示式並不複雜。
正則表示式用來匹配複雜的字串非常好用。