linux C语言处理正则表达式
Linux下C语言处理正则表达式——regex.h
具体函数介绍
编译正则表达式函数
int regcomp(regex_t *preg, const char *regex, int cflags);
其中preg用于保存编译后的正则表达式,regex是我们写的正则表达式。cflags标志位后面再说。
先说说regex_t结构体:
对于这个结构体而言,我们只要记住,它是编译后的正则表达式,后面的匹配是用编译后的正则表达式,这样效率更高,而不是使用我们自己写的原始的正则表达式。此外,还要知道regex_t有一个成员re_nsub,它表示“子正则表达式的个数”。所谓“子正则表达式”就是圆括号里面的正则表达式。可能还是有点懵。没关系,慢慢来!我们使用正则表达式的一个主要目的是提取满足条件的部分。比如有个字符串username=阿星&sex=女,现在我们想提取用户名,也是就“阿星”,那么我们的正则表达式应该写成: username=([^&]*)&,也就是将匹配“阿星”的正则表达式放到圆括号中,作为整个表达式的一个子表达式。后面我们执行regexec函数后,就可以得到“阿星”(后面再讲)。
再来说说cflags:
cflags 的取值有:REG_EXTENDED、REG_ICASE、REG_NOSUB和REG_NEWLINE。这四个值可以单独使用,也可以用按位与联合使用。
其中:
REG_EXTENDED:
意思是,解释正则表达式时使用扩展的正则表达式语法。POSIX规范将正则表达式的实现方法分为了两种:基本正则表达式(BRE)和扩展正则表 达式(ERE)。
BRE和ERE到底有什么区别?其实仅仅是元字符的不同!在BRE方式中,只承认^ 、$、 . 、[ 、] 、*这些是元字符,所有其他的字符都被识别为文字字符。而ERE中,则添加了(、 ) 、{ 、} 、?、 + |、等元字符(及其相关功能)。grep命令默认支持BRE,要想支持ERE需要使用-E选项。
REG_ICASE:
如果编译正则表达式时使用了这个标志,那么在用regexec()函数进行匹配时,就忽略大小写。
REG_NOSUB:
如果使用了这个选项得到的编译后的正则表达式,在被后面的regexec()函数使用时,regexec()的nmatch参数和pmatch参数将会被忽略(后面再讲)
REG_NEWLINE:
一开始我对这个标志位的理解非常模糊,网上很多人解释的也不清楚。经过我的反复试验,终于明白了。
其实REG_NEWLINE的作用就两个:
1、 使^和$有效。
2、 绝对不匹配换行符。
相信大家也都看过Linux中的man page。对于REG_NEWLINE这个标志位的解释,在man page中用了四句话。
我们先来看后两句:
Match-beginning-of-line operator (^) matches the empty string immediately after a newline, regardless of whether eflags, the execution flags of regexec(), contains REG_NOTBOL.
Match-end-of-line operator ($) matches the empty string immediately before a newline, regardless of whether eflags contains REG_NOTEOL.
这两句的意思其实就是,是^匹配一行的开始位置,$匹配一行的结束位置(如果没有使用REG_NEWLINE,这两个字符将被当做普通字符)。并且使REG_NOTBOL和REG_NOTEOL无效。
举两个例子:
有字符串:
username=xinger&sex=girl&age=22\r\nschool=BIT&husband=qinger\r\n&like=study&look=pretty\r\n
如果我们没有使用REG_NEWLINE标志,那么正则表达式^school=([^&]*)将不能匹配,因为这里^被解释成了普通字符,而不是一行的开始。
如果我们加上REG_NEWLINE标志,那么将匹配成school=BIT,此时^不再是普通字符,而是匹配一行的开始。
再比如正则表达式age=([^$]*),如果没有使用REG_NEWLINE,将匹配成:
age=22\r\nschool=BIT&husband=qinger\r\n&like=study&look=pretty\r\n
还是因为$被解释成了普通字符,
比如我们在原字符串中添加一个$,变成
username=xinger&sex=girl&age=22\r\nschool=$BIT&husband=$qinger\r\n&like=study&look=pretty\r\n
那么匹配结果变成了age=22\r\nschool=,原因依然是:把$当成了普通字符。
在来看前两句:
Match-any-character operators don't match a newline.
A nonmatching list ([^...]) not containing a newline does not match a newline.
这两句的意思说白了,就是保证不匹配换行符。比如第一句,意思是匹配任意字符的元字符也不匹配新的一行(好乱呀)。什么意思呢?就是比如说点(.)本来匹配所有的字符(注意,在POSIX中点匹配所有字符!!!和我们平时学的不一样。)但是如果使用了REG_NEWLINE标志,则不匹配换行符\r\n。
还是举个例子吧:
有字符串:
username=xinger&sex=girl&age=22\r\nschool=BIT&husband=$qinger\r\n&like=study&look=pretty\r\n
有正则表达式:sex=([^@]*),如果没有REG_NEWLINE标志,匹配结果是:
sex=girl&age=22\r\nschool=BIT&husband=$qinger\r\n&like=study&look=pretty\r\n
因为[^@]匹配所有不是@的字符。但是如果我们加上了REG_NEWLINE,那么匹配结果为:sex=girl&age=22,原因是REG_NEWLINE保证了绝不匹配换行符!!!其实就相当于[^@\r\n]不加REG_NEWLINE。
在比如,有正则表达式sex=(.*),我们前面提到过:点在POSIX中匹配任意字符(’\0’除外),所以点也匹配换行符,所以匹配结果为:
sex=girl&age=22\r\nschool=BIT&husband=$qinger\r\n&like=study&look=pretty\r\n
但是,如果我们使用了REG_NEWLINE,则保证不会匹配换行符,匹配结果就变成了:sex=girl&age=22。
最后说说返回值:
成功返回0,失败可以用regerror获取失败码。
用编译后的正则表达式进行匹配
int regexec(const regex_t *preg, const char *string, size_t nmatch,
regmatch_t pmatch[], int eflags);
regexec函数用上一步中编译好的正则表达式preg对string内容进行匹配,并将匹配结果以记录字节偏移量的形式保存在pmatch数组中。
首先看看regmatch_t结构体:
regmatch_t 是一个结构体数据类型,在regex.h中定义:
typedef struct
{
regoff_t rm_so;
regoff_t rm_eo;
} regmatch_t;
regexec函数将用匹配的子字符串的起止地址填充pmatch结构体,pmatch[0]对应的是整个正则表达式的匹配结果的起止地址;pmatch[i]则对应存储了第i个子匹配字符串的起止地址。(rm_so表示起始位置距离首地址的偏移量,rm_eo表示结束位置距离首地址的偏移量+1,如果rm_so为-1则表示该子表达式没有匹配)。nmatch表示pmatch结构体数组的元素的个数,它至少应该是子表达式的个数加1(因为0下标存储的是整个表达式的匹配结果)。
再来说说eflags:
首先一点,如果regcomp中使用了REG_NEWLINE变量,这个标志位是无效的!
这个标志位有两个取值:REG_NOTBOL和REG_NOTEOL,作用就是:如果设置了相应的标志位,那么含有^或$,而且含义是一行开始,或结束(比如^也可以解释成非),那么该正则表达式将永远不会匹配!!!。
最后说说返回值:
成功返回0,REG_NOMATCH表示失败。
将错误码转换成错误信息
size_t regerror(int errcode, const regex_t *preg, char *errbuf,
size_t errbuf_size);
该函数用于将regcomp或regexec返回的错误码转换成错误字符串信息。
参数errcode表示那两个函数返回的错误码,preg是regcomp编译后的正则表达式,errbuf用于存储错误信息字符串,errbuf_size是errbuf的大小。
释放regex_t结构体
void regfree(regex_t *preg);
regcomp函数会填写regex_t结构体的元素,这之中需要为某些元素开辟存储空间,而regfree函数就是释放这些空间的。
千万记得最后要调用regfree释放空间,否则会造成内存泄漏。
最后附上一个小例子:
#include <sys/types.h>
#include <regex.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h> char *pick_regex(const char *string,const char *pattern)
{
int err;
char errbuf[];
regex_t compiled;
if((err = regcomp(&compiled,pattern,REG_EXTENDED|REG_ICASE|REG_NEWLINE)) != )
{
regerror(err,&compiled,errbuf,sizeof(errbuf));
printf("err:%s\n",errbuf);
return NULL;
} regmatch_t pmatch[];
err = regexec(&compiled,string,,pmatch,REG_NOTBOL);
if(err != )
{
printf("未匹配成功!\n");
return NULL;
}
if(compiled.re_nsub != )
return NULL;
if(pmatch[].rm_so == -)
return NULL; int len = pmatch[].rm_eo - pmatch[].rm_so;
char *value = (char *)malloc(len + );
if(value == NULL)
return NULL;
memset(value,,len + );
memcpy(value,string + pmatch[].rm_so,len);
//free(value);
regfree(&compiled);//切记最后要释放掉,否则会造成内存泄露 return value;
} int main()
{
const char *string = "username=xinger&sex=girl&age=22\r\nschool=BIT&husband=qinger\r\n&like=study&look=pretty\r\n";
const char *pattern = "school=([^&]*)";
char *value = pick_regex(string,pattern);
printf("提取的值为:%s\n",value); return ;
}
如果你觉得对你有用,就点个赞吧~~~
linux C语言处理正则表达式的更多相关文章
- C语言使用正则表达式
http://blog.chinaunix.net/uid-479984-id-2114941.html C语言使用正则表达式 据说一个好的程序员是会使用DB和Regular Expression的程 ...
- C语言调用正则表达式
标准的C和C++都不支持正则表达式,但有一些函数库可以辅助C/C++程序员完成这一功能,其中最著名的当数Philip Hazel的Perl-Compatible Regular Expression库 ...
- 转载~kxcfzyk:Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解
Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解 多线程c语言linuxsemaphore条件变量 (本文的读者定位是了解Pthread常用多线程API和Pthread互斥锁 ...
- Linux C语言操作MySQL
原文:Linux C语言操作MySQL 1.MySQL数据库简介 MySQL是一个开源码的小型关系数据库管理系统,体积小,速度快,总体成本低,开源.MySQL有以下特性: (1) 使用C和C++编写, ...
- linux c语言定时器
原文来自于:http://hi.baidu.com/opetrhsxszbckzd/item/126966cae5f9524aa9ba94f5 我只是把其重新排版标注一下. linux c语言定时器 ...
- Linux改变语言设置的命令
--Linux语言设置--------------2013/09/22Linux中语言的设置和本地化设置真是一个很繁琐的事情,时不时的会出现乱码的情况,在这篇文章中讨论的是shell中出现乱码的一些解 ...
- linux c语言 select函数用法
linux c语言 select函数用法 表头文件 #i nclude<sys/time.h> #i nclude<sys/types.h> #i nclude<unis ...
- Linux C语言小程序
Linux C语言小程序 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include & ...
- Linux C 语言之 Hello World 详解
目录 Linux C 语言之 Hello World 详解 第一个 C 语言程序 程序运行原理 编译,链接 运行时 链接库 编译器优化 Hello World 打印原理 stdout, stdin 和 ...
随机推荐
- [leetcode-495-Teemo Attacking]
In LLP world, there is a hero called Teemo and his attacking can make his enemy Ashe be in poisoned ...
- python迭代器生成器(二)
其他内置类型迭代器 除了文件以及列表这样的实际的序列外,其他类型也有适合的迭代器. 遍历字典的经典方法是明确的获取其键的列表. 在最近的python版本中,字典有一个迭代器,在迭代环境中,会自动一次返 ...
- mybatis学习笔记(四)-- 为实体类定义别名两种方法(基于xml映射)
下面示例在mybatis学习笔记(二)-- 使用mybatisUtil工具类体验基于xml和注解实现 Demo的基础上进行优化 以新增一个用户为例子,原UserMapper.xml配置如下: < ...
- AT&T汇编helloworld
摘自:http://blog.163.com/guixl_001/blog/static/417641042012112102642703/ 代码: #hello.s .data # 数据段声明 ms ...
- 搭建SSM项目框架全过程及思考
1.前言 之前都是在现有框架下进行写代码或者总是看一些别人的架构,总会眼高手低.于是打算自己完整的走一遍流程,同时把所遇到的问题,思考的问题记下来,供大家参考.由于是工作年限不高,属于新手,不足之处还 ...
- PHP运算符知识点
表达式 几乎所写的任何东西都是一个表达式,简单却最精确的定义一个表达式的方式就是"任何有值的东西". 算术运算符 Php中常用的有:+.-.*./.%(取模,得到余数) 左+ - ...
- 用js写一个回车键盘事件
用js来监听键盘事件,代码如下: <script type="text/javascript" language=JavaScript charset="UTF-8 ...
- poj_3468: A Simple Problem with Integers (树状数组区间更新)
题目是对一个数组,支持两种操作 操作C:对下标从a到b的每个元素,值增加c: 操作Q:对求下标从a到b的元素值之和. 这道题也可以用线段树解,本文不做描述,下面分析如何用树状数组来解决这道题. 先把问 ...
- input复选框操作的部分高频率使用代码
1. 获取单个checkbox选中项(三种写法): $("input:checkbox:checked").val() 或者 $("input:[type='checkb ...
- 如何得到iPhone手机的UUID
背景 测试ad-hoc打包方式打出来的包,必须在证书里面配置手机的uuid才能安装. 这样就需要获取iPhone手机的uuid来进行证书配置 一般来说iPhone手机可以安装通过Apple发布的软件. ...