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格式,具体数字大小可以另行判断在这里插入图片描述

发布了52 篇原创文章 · 获赞 81 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/xiaoma_2018/article/details/102492729