正則表達式

正則表達式

基本概念

字符 含義 舉例
. 匹配任意一個字符 如“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。

參數說明:

  1. regex_t是一個結構體數據類型,用來存放編譯後的正則表達式,其成員re_nsub用來存儲正則表達式組合的子正則表達式的個數。

  2. pattern指向要編譯的正則表達式字符串。

  3. 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。

參數說明:

  1. compiled是使用函數regcomp編譯好的正則表達式;
  2. string是需要匹配的目標字符串;
  3. nmatch是regmatch_t結構體數組的長度;
  4. matchptr是regmatch_t類型的結構體數組,存放匹配字符串的位置信息;
  5. 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以返回一個包含錯誤信息的字符串。

參數說明:

  1. errcode是由函數regexec或者regcomp返回的錯誤代號;
  2. compiled是已經編譯好的正則表達式,其值可以爲NULL;
  3. buffer指向用來存放錯誤信息的字符串內存空間;
  4. 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(&reg,pattern,flag);
  //執行正則表達式和緩存的比較
  status=regexec(&reg,buf,nmatch,pmatch,0);
  //打印匹配的字符串
  for(i=pmatch[0].rm_so;i<pmatch[0].rm_eo;++i){
    putchar(buf[i]);
  }
  printf("\n");
  regfree(&reg);
  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(&regex, 0, sizeof(regex));
    err = re_compile_pattern(pattern, strlen(pattern), &regex);
    if (NULL == err)
    {
        struct re_registers regs;
        memset(&regs, 0, sizeof(regs));
        re_set_registers(&regex, &regs, 0, NULL, NULL);
        num = re_match(&regex, string, strlen(string), 0, &regs);

        /* 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(&regex, &regs);
        regfree(&regex);
    }
    return num;
}

發佈了68 篇原創文章 · 獲贊 4 · 訪問量 9139
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章