正則表達式
基本概念
字符 | 含義 | 舉例 |
---|---|---|
. | 匹配任意一個字符 | 如“abc.”,可以匹配abc2、abcd、abc%等 |
[] | 匹配括號中的任意一個字符 | 如“[abc]d”,可以匹配ad、bd、cd |
- | 在[]括號範圍內表示範圍 | 如“[0-9]”,表示匹配0至9中任意一個數字 |
^ | 位於[]內開頭,匹配除括號內字符以外的任意字符 | 如“[^ab]”,表示匹配除了a、b之外的其他字符 |
? | 緊跟其前面的單元匹配零次或者一次 | |
+ | 緊跟其前面的單元匹配一次或者多次 | |
* | 緊跟其前面的單元匹配零次或者多次 | |
{N} | 緊跟其前面的單元匹配精確的N次 | 如“k{3}”,表示精確匹配kkk。 |
{N,} | 緊跟其前面的單元匹配至少N次 | |
{,M} | 緊跟其前面的單元匹配最多M次 | |
{N,M} | 緊跟其前面的單元匹配至少N次,最多M次 | |
^ | 匹配行首的位置 | |
$ | 匹配行尾的位置 | |
\< | 匹配單詞開頭的位置 | |
\> | 匹配單詞結尾的位置 | |
\b | 匹配單詞的邊界 | 如“\bA.{3}T\b”,表示匹配類似A123t、AXYZT等單詞 |
\B | 匹配非單詞邊界 | 如“\Bh\B”,表示匹配的h不在單詞邊界,如host則不符合,因爲h在單詞的邊界,而she則符合匹配。 |
| | 連接兩個子表達式,表示或的關係 | 如“n(ei|mn)”,匹配nei或者nmn |
() | 將正則表達式部分組成分組,可引用分組 | |
\ | 轉義字符 | |
\d | 匹配數字字符,效果同[0-9] | |
\D | 匹配非數字字符,效果同[0-9],或者同[\d] | |
\w | 匹配單詞字符,效果同[_a-zA-Z0-9] | |
\W | 匹配非單詞字符 | |
\s | 匹配空白字符,效果同[ \t\n\r],注意括號中包括空格 | |
\S | 匹配非空白字符 | |
() | 分組、子模式(subpattern) | |
\1、\2… | 通過後向引用重用捕獲內容 | 如“(the)(china people) \2 \1”,這裏的第一個分組是the、第二個分組是china people,則\1表示第一個分組,\2表示第二個分組。 |
(?:name) | 非捕獲分組 | 如“(?:the|THE)”,非捕獲分組不會將其存儲在內存,無法後向引用 |
C語言實現正則表達式
標準的C與C++都不支持正則表達式,但是在某些場景下,正則表達式存在可以爲程序帶來便利。
在C語言中,一些庫函數可以幫助我們實現在C中使用正則表達式的訴求。
以下介紹在Linux環境下C語言中處理正則表達式的常用函數。
regcomp函數
函數原型爲:
#include<regex.h>
int regcomp(regex_t *compiled, const char *pattern, int cflags);
函數作用:將指定的正則表達式格式pattern編譯成一種特定的數據格式compiled,這樣可以使得正則表達式的匹配更加有效。函數執行成功返回0。
參數說明:
-
regex_t是一個結構體數據類型,用來存放編譯後的正則表達式,其成員re_nsub用來存儲正則表達式組合的子正則表達式的個數。
-
pattern指向要編譯的正則表達式字符串。
-
cflags是標誌位。可以取值爲:
a、REG_EXTENDED:以功能更加強大的擴展正則表達式的方式進行匹配
b、REG_ICASE:匹配字母時,忽略大小寫;
c、REG_NOSUB:不用存儲匹配後的結果;
d、REG_NEWLINE:識別換行符,則符號^與$可以分別從行首與行尾開始匹配。
###regexec函數
函數原型爲:
#include<regex.h>
int regexec(regex_t *compiled, char *string, size_t nmatch, regmatch_t matchptr[], int eflags);
函數作用:使用正則表達式執行匹配目標文本。如果在調用函數regcomp編譯正則表達式時,沒有指定cflags標誌位爲REG_NEWLINE,則默認情況下忽略換行符,即將整個文本內的字符串當作一個整體來處理。函數執行成功返回0。
參數說明:
- compiled是使用函數regcomp編譯好的正則表達式;
- string是需要匹配的目標字符串;
- nmatch是regmatch_t結構體數組的長度;
- matchptr是regmatch_t類型的結構體數組,存放匹配字符串的位置信息;
- eflags取值爲REG_NOTBOL,即讓特殊字符^無作用,eflags取值爲REG_NOTEOL,即讓特殊字符$無作用。
regmatch_t是一個結構體數據類型:
typedef struct {
regoff_t rm_so; /* 存放匹配字符串在目標字符串中的起始位置 */
regoff_t rm_eo; /* 存放匹配字符串在目標字符串中的結束位置 */
} regmatch_t;
/* 通常以數組的形式定義一組regmatch_t結構,因爲往往正則表達式中還包含子正則表達式,即存在分組
數組0單元存放主正則表達式的位置
數組1、2、3...依次存放子正則表達式的位置 */
regfree函數
函數原型爲:
#include<regex.h>
void regfree(regex_t *compiled);
函數作用:使用完編譯好的正則表達式後,或者需要重新編譯其他的正則表達式時,需要使用函數regfree清空compiled指向的結構體內容。
regerror函數
函數原型爲:
#include<regex.h>
size_t regerror(int errcode, regex_t *compiled, char *buffer, size_t length);
函數作用:當執行regexec或者regcomp產生錯誤的時候,可以調用函數regerror以返回一個包含錯誤信息的字符串。
參數說明:
- errcode是由函數regexec或者regcomp返回的錯誤代號;
- compiled是已經編譯好的正則表達式,其值可以爲NULL;
- buffer指向用來存放錯誤信息的字符串內存空間;
- length指明buffer的長度,如果錯誤信息的長度大於該值,則函數自動截斷超出的字符串。
範例
#include<stdio.h>
#include<sys/types.h>
#include<regex.h>
int my_match(char* pattern,char* buf){
int status,i;
int flag=REG_EXTENDED;
regmatch_t pmatch[1];
const size_t nmatch=1;
regex_t reg;
//編譯正則模式
regcomp(®,pattern,flag);
//執行正則表達式和緩存的比較
status=regexec(®,buf,nmatch,pmatch,0);
//打印匹配的字符串
for(i=pmatch[0].rm_so;i<pmatch[0].rm_eo;++i){
putchar(buf[i]);
}
printf("\n");
regfree(®);
return status;
}
int main(){
char pattern[1024]="^[1-9][0-9]{10}$";
char buf[1024]="41509030127";
int status=my_match(pattern,buf);
if(status==REG_NOMATCH)
printf("No match!\n");
else if(0 == status){
printf("match!\n");
}
return 0;
}
C語言中正則表達式的封裝
在C語言中,可以對正則表達式相關的庫函數進行封裝,以實現方便的個人自定義接口。
封裝的頭文件定義了相關的結構體與宏:
typedef struct
{
int start;
int end;
} T_ReReg;
#define FILL_REG(buf, size, string, reg) do { \
if (VALID_REG(reg)) { \
snprintf(buf, size, "%*.*s", LEN_REG(reg), LEN_REG(reg), &string[reg.start]);} \
else { \
snprintf(buf, size, "");} \
} while(0)
#define LEN_REG(reg) (reg.end - reg.start)
#define VALID_REG(reg) (reg.start >= 0 && reg.end >= reg.start)
#define re_free(p) free(p)
封裝的函數定義如下:
static void re_free_registers(struct re_pattern_buffer *buffer, struct re_registers *regs)
{
if ( NULL != buffer && REGS_REALLOCATE == buffer->regs_allocated)
{
if (NULL != regs)
{
if (NULL != regs->start)
{
re_free(regs->start);
regs->start = NULL;
}
if (NULL != regs->end)
{
re_free(regs->end);
regs->end = NULL;
}
}
buffer->regs_allocated = REGS_UNALLOCATED;
}
}
/* 通常以數組的形式定義一組T_ReReg結構,因爲往往正則表達式中還包含子正則表達式,即存在分組
數組0單元存放主正則表達式的位置
數組1、2、3...依次存放子正則表達式的位置 */
int cp_reMatch(const char *pattern, const char *string, T_ReReg *reRegs, unsigned int *regNum)
{
struct re_pattern_buffer regex;
const char *err = NULL;
int num = -1;
re_set_syntax(RE_SYNTAX_POSIX_EGREP);
memset(®ex, 0, sizeof(regex));
err = re_compile_pattern(pattern, strlen(pattern), ®ex);
if (NULL == err)
{
struct re_registers regs;
memset(®s, 0, sizeof(regs));
re_set_registers(®ex, ®s, 0, NULL, NULL);
num = re_match(®ex, string, strlen(string), 0, ®s);
/* fill regular expression registers */
if ((NULL != reRegs) && (NULL != regNum) && ((*regNum) > 0))
{
unsigned int i;
for (i = 0; (i < regs.num_regs) && (i < *regNum); i++)
{
reRegs[i].start = regs.start[i];
reRegs[i].end = regs.end[i];
}
*regNum = i;
}
re_free_registers(®ex, ®s);
regfree(®ex);
}
return num;
}