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格式,具体数字大小可以另行判断
所有博客均在CSDN首发 Caso_卡索 https://blog.csdn.net/xiaoma_2018