POSIX規定了正則表達式的C語言庫函數,詳見regex(3)。我們已經學習了很多C語言庫函數的用法,讀者應該具備自己看懂man手冊的能力了。本章介紹了正則表達式在grep、sed、awk中的用法,學習要能夠舉一反三,請讀者根據regex(3)自己總結正則表達式在C語言中的用法,寫一些簡單的程序,例如驗證用戶輸入的IP地址或email地址格式是否正確。
C語言處理正則表達式常用的函數有regcomp()、regexec()、regfree()和regerror(),一般分為三個步驟,如下所示:
C語言中使用正則表達式一般分為三步:
編譯正則表達式 regcomp()
匹配正則表達式 regexec()
釋放正則表達式 regfree()
下邊是對三個函數的詳細解釋
這個函數把指定的正則表達式pattern編譯成一種特定的數據格式compiled,這樣可以使匹配更有效。函數regexec 會使用這個數據在目標文本串中進行模式匹配。執行成功返回0。
int regcomp (regex_t *compiled, const char *pattern, int cflags) /* 是一個結構體數據類型,用來存放編譯后的正則表達式,它的成員re_nsub 用來存儲正則表達式中的子正則表達式的個數,子正則表達式就是用圓括號包起來的部分表達式。 */regex_t pattern //是指向我們寫好的正則表達式的指針。cflags //有如下4個值或者是它們或運算(|)后的值:REG_EXTENDED //以功能更加強大的擴展正則表達式的方式進行匹配。REG_ICASE //匹配字母時忽略大小寫。REG_NOSUB //不用存儲匹配后的結果,只返回是否成功匹配。如果設置該標志位,那么在regexec將忽略nmatch和pmatch兩個參數。REG_NEWLINE //識別換行符,這樣'$'就可以從行尾開始匹配,'^'就可以從行的開頭開始匹配。
當我們編譯好正則表達式后,就可以用regexec 匹配我們的目標文本串了,如果在編譯正則表達式的時候沒有指定cflags的參數為REG_NEWLINE,則默認情況下是忽略換行符的,也就是把整個文本串當作一個字符串處理。
執行成功返回0。
regmatch_t 是一個結構體數據類型,在regex.h中定義:
typedef struct {regoff_t rm_so;regoff_t rm_eo; } regmatch_t;
成員rm_so 存放匹配文本串在目標串中的開始位置,rm_eo 存放結束位置。通常我們以數組的形式定義一組這樣的結構。因為往往我們的正則表達式中還包含子正則表達式。數組0單元存放主正則表達式位置,后邊的單元依次存放子正則表達式位置。
int regexec (regex_t *compiled, char *string, size_t nmatch, regmatch_t matchptr[], int eflags) compiled //是已經用regcomp函數編譯好的正則表達式。 string // 是目標文本串。 nmatch // 是regmatch_t結構體數組的長度。 matchptr regmatch_//t類型的結構體數組,存放匹配文本串的位置信息。 eflags 有兩個值: REG_NOTBOL //讓特殊字符^無作用 REG_NOTEOL //讓特殊字符$無作用
當我們使用完編譯好的正則表達式后,或者要重新編譯其他正則表達式的時候,我們可以用這個函數清空compiled指向的regex_t結構體的內容,請記住,如果是重新編譯的話,一定要先清空regex_t結構體。
void regfree (regex_t *compiled)
當執行regcomp 或者regexec 產生錯誤的時候,就可以調用這個函數而返回一個包含錯誤信息的字符串。
size_t regerror (int errcode, regex_t *compiled, char *buffer, size_t length)errcode //是由regcomp 和 regexec 函數返回的錯誤代號。 compiled //是已經用regcomp函數編譯好的正則表達式,這個值可以為NULL。 buffer //指向用來存放錯誤信息的字符串的內存空間。 length //指明buffer的長度,如果這個錯誤信息的長度大于這個值,則regerror 函數會自動截斷超出的字符串,但他仍然會返回完整的字符串的長度。所以我們可以用如下的方法先得到錯誤字符串的長度。
例如: size_t length = regerror (errcode, compiled, NULL, 0);
測試用例:
#include <sys/types.h> #include <regex.h> #include <stdio.h>int main(int argc, char ** argv) {if (argc != 3) {printf("Usage: %s RegexString Text\n", argv[0]);return 1;}const char * pregexstr = argv[1];const char * ptext = argv[2];regex_t oregex;int nerrcode = 0;char szerrmsg[1024] = {0};size_t unerrmsglen = 0;if ((nerrcode = regcomp(&oregex, pregexstr, REG_EXTENDED|REG_NOSUB)) == 0) {if ((nerrcode = regexec(&oregex, ptext, 0, NULL, 0)) == 0) {printf("%s matches %s\n", ptext, pregexstr);regfree(&oregex);return 0;}}unerrmsglen = regerror(nerrcode, &oregex, szerrmsg, sizeof(szerrmsg));unerrmsglen = unerrmsglen < sizeof(szerrmsg) ? unerrmsglen : sizeof(szerrmsg) - 1;szerrmsg[unerrmsglen] = '\0';printf("ErrMsg: %s\n", szerrmsg);regfree(&oregex);return 1; }
匹配網址:
./a.out "http:\/\/www\..*\.com" "http://www.taobao.com"
./a.out "^[a-zA-Z0-9]+@[a-zA-Z0-9]+.[a-zA-Z0-9]+" "itcast123@itcast.com" ./a.out "\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" "itcast@qq.com" 注:\w匹配一個字符,包含下劃線
除了gnu提供的函數外,還常用PCRE處理正則,全稱是Perl Compatible Regular Ex-pressions。從名字我們可以看出PCRE庫是與Perl中正則表達式相兼容的一個正則表達式庫。PCRE是免費開源的庫,它是由C語言實現的,這里是它的官方主頁:http://www.pcre.org/,感興趣的朋友可以在這里了解更多的內容。 要得到PCRE庫,可以從這里下載:http://sourceforge.net/projects/pcre/files/
PCRE++是一個對PCRE庫的C++封裝,它提供了更加方便、易用的C++接口。這里是它的官方主頁:http://www.daemon.de/PCRE,感興趣的朋友可以在這里了解更多的內容。 要得到PCRE++庫,可以從這里下載:http://www.daemon.de/PcreDownload
另外c++中常用 boost regex。