linux C語言處理Regex

來源:互聯網
上載者:User

標籤:any   實現   exec   div   結構   use   關係   gre   類型   

Linux下C語言處理Regex——regex.h具體函數介紹編譯Regex函數
int regcomp(regex_t *preg, const char *regex, int cflags);

 

其中preg用於儲存編譯後的Regex,regex是我們寫的Regex。cflags標誌位後面再說。

先說說regex_t結構體:

對於這個結構體而言,我們只要記住,它是編譯後的Regex,後面的匹配是用編譯後的Regex,這樣效率更高,而不是使用我們自己寫的原始的Regex。此外,還要知道regex_t有一個成員re_nsub,它表示“子Regex的個數”。所謂“子Regex”就是圓括弧裡面的Regex。可能還是有點懵。沒關係,慢慢來!我們使用Regex的一個主要目的是提取滿足條件的部分。比如有個字串username=阿星&sex=女,現在我們想提取使用者名稱,也是就“阿星”,那麼我們的Regex應該寫成: username=([^&]*)&,也就是將匹配“阿星”的Regex放到圓括弧中,作為整個運算式的一個子運算式。後面我們執行regexec函數後,就可以得到“阿星”(後面再講)。

再來說說cflags:

cflags 的取值有:REG_EXTENDED、REG_ICASE、REG_NOSUB和REG_NEWLINE。這四個值可以單獨使用,也可以用按位與聯合使用。

其中:

REG_EXTENDED:

意思是,解釋Regex時使用擴充的Regex文法。POSIX規範將Regex的實現方法分為了兩種:基本Regex(BRE)和擴充正則表 達式(ERE)。

BRE和ERE到底有什麼區別?其實僅僅是元字元的不同!在BRE方式中,只承認^ 、$、 . 、[ 、] 、*這些是元字元,所有其他的字元都被識別為文字字元。而ERE中,則添加了(、 ) 、{ 、} 、?、 + |、等元字元(及其相關功能)。grep命令預設支援BRE,要想支援ERE需要使用-E選項。

REG_ICASE:

如果編譯Regex時使用了這個標誌,那麼在用regexec()函數進行匹配時,就忽略大小寫。

REG_NOSUB:

如果使用了這個選項得到的編譯後的Regex,在被後面的regexec()函數使用時,regexec()的nmatch參數和pmatch參數將會被忽略(後面再講)

 

 

REG_NEWLINE:

一開始我對這個標誌位的理解非常模糊,網上很多人解釋的也不清楚。經過我的反覆實驗,終於明白了。

其實REG_NEWLINE的作用就兩個:

1、         使^和$有效。

2、         絕對不匹配分行符號。

相信大家也都看過Linux中的man page。對於REG_NEWLINE這個標誌位的解釋,在man page中用了四句話。

我們先來看後兩句:

Match-beginning-of-line operator (^) matches  the  empty  string immediately  after  a newline, regardless of whether eflags, the execution flags of regexec(), contains REG_NOTBOL.

Match-end-of-line operator ($) matches the empty string  immediately  before  a  newline, regardless of whether eflags contains REG_NOTEOL.

這兩句的意思其實就是,是^匹配一行的開始位置,$匹配一行的結束位置(如果沒有使用REG_NEWLINE,這兩個字元將被當做一般字元)。並且使REG_NOTBOL和REG_NOTEOL無效。

舉兩個例子:

有字串:

username=xinger&sex=girl&age=22\r\nschool=BIT&husband=qinger\r\n&like=study&look=pretty\r\n

如果我們沒有使用REG_NEWLINE標誌,那麼Regex^school=([^&]*)將不能匹配,因為這裡^被解釋成了一般字元,而不是一行的開始。

如果我們加上REG_NEWLINE標誌,那麼將匹配成school=BIT,此時^不再是一般字元,而是匹配一行的開始。

再比如Regexage=([^$]*),如果沒有使用REG_NEWLINE,將匹配成:

age=22\r\nschool=BIT&husband=qinger\r\n&like=study&look=pretty\r\n

還是因為$被解釋成了一般字元,

比如我們在原字串中添加一個$,變成

username=xinger&sex=girl&age=22\r\nschool=$BIT&husband=$qinger\r\n&like=study&look=pretty\r\n

那麼匹配結果變成了age=22\r\nschool=,原因依然是:把$當成了一般字元。

在來看前兩句:

Match-any-character operators don‘t match a newline.

A  nonmatching  list ([^...])  not containing a newline does not match a newline.

這兩句的意思說白了,就是保證不匹配分行符號。比如第一句,意思是匹配任一字元的元字元也不匹配新的一行(好亂呀)。什麼意思呢?就是比如說點(.)本來匹配所有的字元(注意,在POSIX中點匹配所有字元!!!和我們平時學的不一樣。)但是如果使用了REG_NEWLINE標誌,則不匹配分行符號\r\n。

還是舉個例子吧:

有字串:

username=xinger&sex=girl&age=22\r\nschool=BIT&husband=$qinger\r\n&like=study&look=pretty\r\n

有Regex:sex=([^@]*),如果沒有REG_NEWLINE標誌,匹配結果是:

sex=girl&age=22\r\nschool=BIT&husband=$qinger\r\n&like=study&look=pretty\r\n

因為[^@]匹配所有不是@的字元。但是如果我們加上了REG_NEWLINE,那麼匹配結果為:sex=girl&age=22,原因是REG_NEWLINE保證了絕不匹配分行符號!!!其實就相當於[^@\r\n]不加REG_NEWLINE。

在比如,有Regexsex=(.*),我們前面提到過:點在POSIX中匹配任一字元(’\0’除外),所以點也匹配分行符號,所以匹配結果為:

sex=girl&age=22\r\nschool=BIT&husband=$qinger\r\n&like=study&look=pretty\r\n

但是,如果我們使用了REG_NEWLINE,則保證不會匹配分行符號,匹配結果就變成了:sex=girl&age=22。

最後說說傳回值:

成功返回0,失敗可以用regerror擷取失敗碼。

用編譯後的Regex進行匹配
int regexec(const regex_t *preg, const char *string, size_t nmatch,                   regmatch_t pmatch[], int eflags);

 

 

regexec函數用上一步中編譯好的Regexpreg對string內容進行匹配,並將匹配結果以記錄位元組位移量的形式儲存在pmatch數組中。

首先看看regmatch_t結構體:

regmatch_t 是一個結構體資料類型,在regex.h中定義:            

typedef struct{   regoff_t rm_so;   regoff_t rm_eo;} regmatch_t;

 

 

regexec函數將用匹配的子字串的起止地址填充pmatch結構體,pmatch[0]對應的是整個Regex的匹配結果的起止地址;pmatch[i]則對應儲存了第i個子匹配字串的起止地址。(rm_so表示起始位置距離首地址的位移量,rm_eo表示結束位置距離首地址的位移量+1,如果rm_so為-1則表示該子運算式沒有匹配)。nmatch表示pmatch結構體數組的元素的個數,它至少應該是子運算式的個數加1(因為0下標儲存的是整個運算式的匹配結果)。

 

再來說說eflags:

首先一點,如果regcomp中使用了REG_NEWLINE變數,這個標誌位是無效的!

這個標誌位有兩個取值:REG_NOTBOL和REG_NOTEOL,作用就是:如果設定了相應的標誌位,那麼含有^或$,而且含義是一行開始,或結束(比如^也可以解釋成非),那麼該Regex將永遠不會匹配!!!。

最後說說傳回值:

成功返回0,REG_NOMATCH表示失敗。

 

將錯誤碼轉換成錯誤資訊
size_t regerror(int errcode, const regex_t *preg, char *errbuf,                       size_t errbuf_size);

 

該函數用於將regcomp或regexec返回的錯誤碼轉換成錯誤字串資訊。

參數errcode表示那兩個函數返回的錯誤碼,preg是regcomp編譯後的Regex,errbuf用於儲存錯誤資訊字串,errbuf_size是errbuf的大小。

 

釋放regex_t結構體
void regfree(regex_t *preg);

 

regcomp函數會填寫regex_t結構體的元素,這之中需要為某些元素開闢儲存空間,而regfree函數就是釋放這些空間的。

千萬記得最後要調用regfree釋放空間,否則會造成記憶體流失。

 

最後附上一個小例子:
#include <sys/types.h>#include <regex.h>#include <stdio.h>#include <string.h>#include <stdlib.h>static int compile_regex(regex_t* compiled,const char* pattern){        char errbuf[1024];     int err;    if(   (err=regcomp(compiled,pattern,REG_EXTENDED|REG_ICASE) ) !=0)    {         regerror(err,compiled,errbuf,sizeof(errbuf));         printf("err:%s\n",errbuf);        return -1;     }     return 0;}int main(){    const char *dest = "username=xinger&sex=girl&age=22\r\nschool=BIT&husband=$qinger\r\n&like=study&look=pretty\r\n";    printf("未經處理資料為:\n%s\n",dest);    const char *pattern = "school=([^&]*)";    int err;    char errbuf[1024];    regex_t compiled;    if((err = regcomp(&compiled,pattern,REG_EXTENDED|REG_ICASE)) != 0)    {         regerror(err,&compiled,errbuf,sizeof(errbuf));         printf("err:%s\n",errbuf);        return -1;    }        regmatch_t pmatch[3];    err = regexec(&compiled,dest,3,pmatch,REG_NOTBOL);    if(err != 0)    {        printf("未匹配成功!\n");        return -1;    }    int i = 0;    for(;i <= (int)compiled.re_nsub;i++)    {        if(pmatch[i].rm_so == -1)            continue;        int len = pmatch[i].rm_eo - pmatch[i].rm_so;        char *value = (char *)malloc(len + 1);        if(value == NULL)            return -1;        memset(value,0,len + 1);        memcpy(value,dest + pmatch[i].rm_so,len);        printf("提取的值為:%s\n",value);        free(value);    }    regfree(&compiled);//切記最後要釋放掉,否則會造成記憶體泄露        return 0;}

 

 如果你覺得對你有用,就點個贊吧~~~

linux C語言處理Regex

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.