标题:使用Linux/Unix/BSD的regex库 出处:Felix021 时间:Sun, 25 Nov 2012 00:01:01 +0000 作者:felix021 地址:https://www.felix021.com/blog/read.php?2099 内容: C/C++标准里头都没有正则表达式,C++还好,可以用上boost::regex,C的话,最简单的还是用系统自带的正则库了。 这个正则库真是相当简单,如果不关心内部琐碎的细节,实际上它只有2个类型、4个函数和7个常量,详细的后面会列出来(或者直接man regex),这里还是直接看例子比较实在: 代码1:email格式检测#include #include #include int main() { //分配一个regex_t regex_t reg; //编译(使用POSIX扩展模式、并忽略大小写),确认编译成功(返回0) assert(regcomp(®, "^[a-z0-9_]+@([a-z0-9-]+\\.)+[a-z0-9]+$", REG_EXTENDED | REG_ICASE) == 0); int ret = regexec(®, "steve@rim.jobs", 0, NULL, 0); //执行搜索 //看看返回值:0表示匹配成功,1表示REG_NOMATCH printf("ret = %d, nomatch = %d\n", ret, REG_NOMATCH); regfree(®); //记得释放空间 } 代码2:匹配xml的tag,取出key/valueint main() { const char *str = "value"; regex_t reg; assert(regcomp(®, "<([^>]*)>([^<]*)", REG_EXTENDED) == 0); //编译 const int nr_match = 3; //串本身 + 2个子匹配 regmatch_t matches[nr_match]; //存储匹配的起始位置和结束位置 int ret = regexec(®, str, nr_match, matches, 0); if (ret == 0) { //匹配成功 for (int i = 0; i < nr_match; i++) { //先输出整个串,再依次输出子匹配 for (int j = matches[i].rm_so; j < matches[i].rm_eo; j++) // [起始, 结束) putchar(str[j]); putchar('\n'); } } else if (ret == REG_NOMATCH) { //匹配失败 printf("no match\n"); } else { //执行错误 char msgbuf[256]; regerror(ret, ®, msgbuf, sizeof(msgbuf)); //输出错误信息至字符数组 printf("error: %s\n", msgbuf); } regfree(®); return 0; } //运行结果: value key value 代码3:找出所有匹配的字符串(regexec只匹配第一个)int main() { regex_t reg; const char *str = "v1v2v3"; assert(regcomp(®, "<([^>]*)>([^<]*)", REG_EXTENDED) == 0); const int nr_match = 3; regmatch_t matches[nr_match]; const char *start = str; while (1) { int ret = regexec(®, start, nr_match, matches, 0); if (ret == 0) { for (int i = 0; i < nr_match; i++) { for (int j = matches[i].rm_so; j < matches[i].rm_eo; j++) putchar(start[j]); putchar('\n'); } start += matches[0].rm_eo; //下次从 这次匹配末尾 开始搜索 continue; } if (ret == REG_NOMATCH) printf("no match\n"); else { char msgbuf[256]; regerror(ret, ®, msgbuf, sizeof(msgbuf)); printf("error: %s\n", msgbuf); } break; } regfree(®); return 0; } //输出: v1 k1 v1 v2 k2 v2 v3 k3 v3 no match ==== 分割线 ==== 上面给出的几个例子能够满足regex的基本使用了,这里把前面提到的2、4、7给列出来,供参考。 //用于储存编译好的正则 typedef struct re_pattern_buffer regex_t ; //用于存储匹配到的位置(起始、结束偏移量,rm_so是RegexMatch_StartOffset的首字母简写) typedef struct { regoff_t rm_so; regoff_t rm_eo; } regmatch_t; //将regex正则表达式 编译存储到preg指向的regex_t中去,该regex_t需要事先分配好。编译成功返回0。 int regcomp(regex_t *preg, const char *regex, int cflags); //其中cflags可以是以下几项的异或 REG_EXTENDED //启用posix扩展模式,(){}+这些字符变成元字符 REG_ICASE //忽略大小写 REG_NOSUB //只匹配,不保存匹配到的正则位置 REG_NEWLINE //启用多行模式:. 不能匹配换行符,且 ^和$可以匹配\n之后的位置和\n之前的位置 //释放编译使额外分配的空间(不会释放regex_t本身) void regfree(regex_t *preg); //执行搜索匹配:查找string中满足preg的第一个串,将串的始末位置保存到pmatch[0].rm_so/rm_eo; //子匹配依次保存到pmatch[1], pmatch[2], ... 调用者要保证匹配的数量不超过nmatch。 //匹配成功返回0,无匹配返回 ,其他是出错(比如参数错误)。 int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags); //其中eflags可以是以下的异或 REG_NOTBOL //无视^规则(Beginning Of Line):将字符串分段匹配的时候,后面可能不希望匹配到^ REG_NOTEOL //无视$规则 Generated by Bo-blog 2.1.0