C語言正則匹配IP實例詳解

  在實際開發中,作一些字符串的匹配時,使用正則表達式來過濾匹配,代碼更加簡潔、匹配更加精準。爲此,想到引入一個問題來總結記錄一下 Linux C 中正則表達式的使用方法。

一、問題描述

  要求用戶輸入一串類似 IP地址 的字符串,該程序通過調用C庫提供的正則表達式接口來實現判斷用戶輸入的 IP 是否合法。

二、匹配 IP地址正則表達式

^[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}$

注意:此表達式只匹配正確的 IP格式,標準IP爲 [0-255].[0-255].[0-255].[255],不判斷用戶輸入的IP值大小,即用戶輸入 999.999.999.999 時,正則匹配爲正確的 IP格式,實際 ip值的大小可通過在程序中判斷是否爲 【0-255】。

三、正則函數接口

C正則函數聲明頭文件爲: <sys/types.h> 和 <regex.h>

  • 首先聲明一個 regex_t preg; 結構體變量,用來存放編譯後的正則表達式,定義在 regex.h
    #ifdef __USE_GNU
    # define __REPB_PREFIX(name) name
    #else
    # define __REPB_PREFIX(name) __##name
    #endif
    struct re_pattern_buffer
    {
    	unsigned char *__REPB_PREFIX(buffer);		//保存已編譯模式的存儲空間
    	unsigned long int __REPB_PREFIX(allocated);	//*buffer指向空間的字節數
    	unsigned long int __REPB_PREFIX(used); 		// 實際buffer使用的字節數
    	reg_syntax_t __REPB_PREFIX(syntax);			// 被編譯正則的語法設置
    	char *__REPB_PREFIX(fastmap);				//指向快速映射的指針
    __RE_TRANSLATE_TYPE __REPB_PREFIX(translate);	//轉換模式類型
    	size_t re_nsub;		// 用來存儲正則表達式中的子正則表達式的個數
    	unsigned __REPB_PREFIX(can_be_null) : 1;	// 如果此模式與空字符串不匹配,則爲0,否則爲1
    /* If REGS_UNALLOCATED, allocate space in the `regs' structure
       for `max (RE_NREGS, re_nsub + 1)' groups.
       If REGS_REALLOCATE, reallocate space if necessary.
       If REGS_FIXED, use what's there.  */
      	#ifdef __USE_GNU
      	# define REGS_UNALLOCATED 0
      	# define REGS_REALLOCATE 1
      	# define REGS_FIXED 2
      	#endif
    	unsigned __REPB_PREFIX(regs_allocated) : 2;
       /* Set to zero when `regex_compile' compiles a pattern; set to one
      	  by `re_compile_fastmap' if it updates the fastmap.  */
    	unsigned __REPB_PREFIX(fastmap_accurate) : 1;
       /* If set, `re_match_2' does not return information about subexpressions.  */
    	unsigned __REPB_PREFIX(no_sub) : 1;
       /* If set, a beginning-of-line anchor doesn't match at the beginning of the string.  */
    	unsigned __REPB_PREFIX(not_bol) : 1;
    	/* Similarly for an end-of-line anchor.  */
    	unsigned __REPB_PREFIX(not_eol) : 1;
    	/* If true, an anchor at a newline matches.  */
    	unsigned __REPB_PREFIX(newline_anchor) : 1;
    }
  • regcomp : 編譯生成正則表達式,
    int regcomp(regex_t *preg, const char *regex, int cflags)
    參數介紹:
      preg:之前定義的 regex_t 結構體變量地址,用來存儲編譯後的正則表達式
      regex:寫好的正則表達式
      cflags:表示要編譯的正則類型
        REG_EXTENDED 以功能更加強大的擴展正則表達式的方式進行匹配
        REG_ICASE 匹配字母時忽略大小寫
        REG_NOSUB 不用存儲匹配後的結果
        REG_NEWLINE 識別換行符,’^’ 行首和行尾 ‘$’
  • regexec:判斷一個字符串是否與之前 regcomp 生成的正則匹配,匹配成功返回 0,失敗返回 REG_NOMATCH
    int regexec(const regex_t *preg, const char *string, size_t nmatch, \
    			regmatch_t pmatch[], int eflags); 
    參數介紹:
      string:待匹配的字符串
      nmatch:regmatch_t 結構體數組的長度
      pmatch[]:regmatch_t 結構體數組,存放匹配字符串的位置信息
      eflag:有REG_NOTBOL 和 REG_NOTEOL
  • regfree:當使用完編譯好的正則表達式後,或者要重新編譯其他正則表達式的時候,用這個函數清空compiled指向的regex_t結構體的內容,如果需要重新編譯,一定要清空regex_t結構體
    void regfree(regex_t *preg);
  • regerror:當執行regcomp 或者regexec 產生錯誤的時候,就可以調用這個函數而返回一個包含錯誤信息的字符串。
    size_t regerror(int errcode, const regex_t *preg, char *errbuf, \
    				size_t errbuf_size);
    參數介紹:
      errcode:是由regcomp 和 regexec 函數返回的錯誤代號
      errbuf:指向存放錯誤信息的字符串的內存空間
      errbuf_size:errbuf 的長度
四、C代碼實現
#include <stdio.h> 
#include <string.h>
#include <regex.h>
#include <sys/types.h>
#define ERROR_SIZE 256
char errbuf[ERROR_SIZE] = {0};

static void check_Ip_Format(regex_t *ipreg, const char *ip_str)
{
	regmatch_t pmatch[1];
	const size_t nmatch = 1;
	int status = regexec(ipreg, ip_str, nmatch, pmatch, 0);
	if(status == 0) {
		printf("Match Successful!\n");
	}
	else if(status == REG_NOMATCH) {
		regerror(status, ipreg, errbuf, ERROR_SIZE);	
		printf("%s\n", errbuf);
		memset(errbuf, 0, ERROR_SIZE);
	}
	return;	
}
int main()
{
	// 999.999.999.999
	char ip_str[20] = {0};
	char *ip_format = "^[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}$";
	// 編譯正則表達式
	regex_t ipreg;
	int reg = regcomp(&ipreg, ip_format, REG_EXTENDED);
	if(reg != 0) {
		regerror(reg, &ipreg, errbuf, ERROR_SIZE);	
		printf("%s\n", errbuf);
		memset(errbuf, 0, ERROR_SIZE);
		return 0;
	}
	while(1) {
		memset(ip_str, 0, 16);
		printf("Please input IP adderss: ");
		scanf("%s", ip_str);
		if(strstr(ip_str, "end")) {
			printf("Stop!!!\n");
			break;
		}
		check_Ip_Format(&ipreg, ip_str);
	}
	regfree(&ipreg);
	return 0;
}
五、執行結果

上面程序能夠匹配出用戶輸入的 ip 是否是數字,並且是否滿足標準IP格式,具體數字大小可以另行判斷在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章