今天有幸(2016/3/19)在上海参加了C++交流会,见到了梦寐已久想见的台湾C++大神老师侯捷,心情十分的激动。侯老师对C++理解的深刻,让人叹为观止。以为他教学的严谨,说话方式娓娓道来,听着非常舒服。末尾附上一张侯老师照片。

  我们接着上文介绍C++11的正则表达式。本节将接着上文遗留问题开始展开,并且将结合网上的一些优秀的博客。

正文

 C++11 支持六种正则表达式语法:

 ECMAScript,

 basic(POSIX Basic Regular Expressions),

extended(POSIX Extended Regular Expressions ),

 awk(POSIX awk) ,

grep(POSIX grep ),

egrep(POSIX grep –E)。其中ECMAScript最为强大。

首先,我们将介绍正则表达式一些通用的基本类型。

1 basic_regex

//basic_regex: 这是一个包含一个正则表达式的模板类。通常有两种特化方式:
a) typedef basic_regex<char> regex;
b) typedef basic_regex<wchar_t> wregex;

2 match_results:

 这个类包含了与给定正则表达式匹配的序列。当empty()成员返回true或者size()成员返回0,表明没有找到匹配项。
否则,当empty()返回false,size()返回值>=1 表明发生了匹配。

//match_results有如下特化方式:
a) typedef match_results<const char*> cmatch;
b) typedef match_results<const wchar_t*> wcmatch;
c) typedef match_results<string::const_iterator> smatch;
d) typedef match_results<wstring::const_iterator> wsmatch;
match[0]:代表整个匹配序列 ;
match[1]:代表第一个匹配子序列;
match[2]: 代表第二个匹配子序列,以此类推。

特别需要注意的是:正则表达式的编写过程中,需要达到上面match[1][2][3]效果的话,必须将每个match数据通过捕获组(capture group)的方式用括号括起来(.*),例如:

regex reg("<(.*)>(.*)</(\\1)>")

如果你把括号删除,显然是没有上面说的那种效果的。其中\1指的是第一个捕获组,\2 当然就是指代第二个啦。

3 sub_match: 该模板类用来表示与一个已标记的子表达式匹配的序列。这个匹配是通过一个迭代器对来表示的,该迭代器对表明了已匹配的正则表达式的一个范围。可以特化为下面几种情况:

a)    typedef sub_match<const char*>              csub_match;
b) typedef sub_match<const wchar_t*> wcsub_match;
c) typedef sub_match<string::const_iterator> ssub_match;
d) typedef sub_match<wstring::const_iterator> wssub_match;

4 迭代器介绍:正则表达式迭代器用来遍历这个正则表达式序列,通过一个迭代器区间来表示匹配的区间。

1. regex_iterator:
a)typedef regex_iterator<const char*> cregex_iterator;
b)typedef regex_iterator<const wchar_t*> wcregex_iterator;
c)typedef regex_iterator<string::const_iterator> sregex_iterator;
d)typedef regex_iterator<wstring::const_iterator> wsregex_iterator; 2. regex_token_iterator:
a) typedef regex_token_iterator<const char*> cregex_token_iterator;
b) typedef regex_token_iterator<const wchar_t*> wcregex_token_iterator;
c) typedef regex_token_iterator<string::const_iterator> sregex_token_iterator;
d) typedef regex_token_iterator<wstring::const_iterator> wsregex_token_iterator;

一些test代码:

     string data = "XML tag: <tag-name>the value</tag-name>.";
cout << "data: " << data << endl << endl;
smatch m;
bool found = regex_search(data, m, regex("<(.*)>(.*)</(\\1)>"));
cout << "m.empty() " << boolalpha << m.empty() << endl;
cout << "m.size() " << m.size() << endl;
if (found)
{
cout << "m.str() " << m.str() << endl;
cout << "m.length() " << m.length() << endl;
cout << "m.position() " << m.position() << endl;
cout << "m.prefix().str() " << m.prefix().str() << endl;
cout << "m.suffix().str() " << m.suffix().str() << endl;
}
for (int i = 0; i < m.size(); i++)
{
cout << "m[" << i << "].size():" << m[i].str() << endl;
cout << "m.str(" << i << "):" << m.str(i) << endl;
cout << "m.position(" << i << "):" << m.position(i) << endl;
}
cout << "match: " << endl;
for (auto pos = m.begin(); pos != m.end(); pos++)
{
cout << " " << *pos << " ";
cout << "(length" << pos->length() << ")" << endl;
}
     //第二个例子
data = "<person>\n"
" <first>Nico</first>\n"
" <last>Josuttis</last>\n"
"</person>\n";
auto pos = data.cbegin();
auto end = data.cend();
regex reg("<(.*)>(.*)</(\\1)>"); for (;regex_search(pos, end, m, reg); pos = m.suffix().first)
{
cout << "match: " << m.str() << endl;
cout << "tag: " << m.str(1) << endl;
cout << "value: " << m.str(2) << endl;
}

  我们要查找的字符串是这样的格式:

  另外,第二个例子中将字符串添加换行符,如果没有添加,将无法辨别<first><last>,最后只能找到<person>。

Regex Iterator:  采用迭代器的方式进行访问或通过for_each()

sregex_iterator pos(data.cbegin(),data.cend(),reg);
sregex_iterator end; for(; pos!=end; ++pos)
{
cout << "match " << pos -> str() << endl;
cout << "tag:" << pos -> str(1) << endl;
cout << "value:" << pos -> str(2) << endl;
} for_each(beg,end,[](const smatch &m){
cout << "match " << pos -> str() << endl;
cout << "tag:" << pos -> str(1) << endl;
cout << "value:" << pos -> str(2) << endl;
});

Regex Token Iterator

1、regex reg("<(.*)>(.*)</(\\1)>");

sregex_token_iterator pos(data.cbegin(),data.cend(),reg,{0,2});//0代表了获取整个match,2代表获取第二个group;-1代表了想知道所有子序列。

2、regex  sep("[[:space:]]*[;,.][[:space:]]*");//以;.,分割。

sregex_token_iterator pos(data.cbegin(),data.cend(),sep,-1);//得到所有子序列。(具体用法请参考c++11标准库,有详细用法和介绍)

小结:

前面2节主要介绍两个函数(regex_search regex_match),但是这两个函数不能定义出在那个位置,我们引入了迭代器、group的概念。下一节主要介绍替换、regex常量以开头说的6种正则表达式语法,最后想通过几个简单的例子练习一下。其实标准库里面说的很清楚,如果不明白的话,建议去买一本侯捷翻译的c++11标准库。

理解C++11正则表达式(2)的更多相关文章

  1. 理解c++11正则表达式 (1)

    概要 C++11提出了正则表达式这个概念,只需在头文件中包含#include<regex>即可.我们可以完成: Match 将整个输入拿来比对匹配某个正则表达式 Search 查找与正则表 ...

  2. C++ 11学习和掌握 ——《深入理解C++ 11:C++11新特性解析和应用》读书笔记(一)

    因为偶然的机会,在图书馆看到<深入理解C++ 11:C++11新特性解析和应用>这本书,大致扫下,受益匪浅,就果断借出来,对于其中的部分内容进行详读并亲自编程测试相关代码,也就有了整理写出 ...

  3. c++11 正则表达式基本使用

    c++ 11 正则表达式 常用的方法 regex_match regex_search regex_replace 等. regex_match 要求正则表达式必须与模式串完全匹配,例如: strin ...

  4. C++11 | 正则表达式(4)

    C++11还支持正则表达式里的子表达式(也叫分组),用sub_match这个类就行了. 举个简单的例子,比如有个字符串"/id:12345/ts:987697413/user:678254& ...

  5. 深入理解C++11【5】

    [深入理解C++11[5]] 1.原子操作与C++11原子类型 C++98 中的原子操作.mutex.pthread: #include<pthread.h> #include <i ...

  6. 深入理解C++11【4】

    [深入理解C++11[4]] 1.基于范围的 for 循环 C++98 中需要告诉编译器循环体界面范围.如for,或stl 中的for_each: int main() { ] = { , , , , ...

  7. 深入理解C++11【3】

    [深入理解C++11[3]] 1.POD类型 Plain Old Data. Plain 表示 了POD是个普通的类型.C++11将POD划分为两个基本概念的合集: 1)平凡的(trivial) 2) ...

  8. 深入理解C++11【2】

    [深入理解C++11[2]] 1.继承构造函数. 当基类拥有多个构造函数的时候,子类不得不一一实现. C++98 可以使用 using 来使用基类的成员函数. #include < iostre ...

  9. 深入理解C++11

    [深入理解C++11] 1.很多 现实 的 编译器 都 支持 C99 标准 中的__ func__ 预定 义 标识符 功能, 其 基本 功能 就是 返回 所在 函数 的 名字. 编译器 会 隐式 地 ...

随机推荐

  1. csqlite编译相关配置问题

    csqlite是非常好用的数据库,同时该数据库是开源的,基于一定原因可能需要编译自己需要的csqlite版本,那么下面介绍内容也会你就会感兴趣了. 这里要实现的目标是使用VS工具能够正确编译csqli ...

  2. ARM 平台上的Linux系统启动流程

    开始学习嵌入式开发就一直在使用Linux系统作为学习的平台,到现在无论是PC机还是ARM开发板都已经能顺利地跑起了Linux系统,但是对Linux 的启动流程还是不甚了解.于是开始各种百度谷歌,当然看 ...

  3. 进程显示,删除,调度 ps, top kill

    ps:查看进程的情况,显示的是某一时间进程的运行状态.ps --help top:也是查看进程的情况,动态显示进程信息! kill:杀死进程的情况, sudo kill --help 查看相关参数 c ...

  4. SVG

    目前SVG在国内的使用并不常见,并且关于svg的相关js库也不多,这里指出两款svg的库Snap.svg和svg.js,Snap.svg张鑫旭的博客上有关于他的使用APi http://www.zha ...

  5. 用开源软件构建App的高效服务端

    1.APP后端的重要性 2.架构目标与选型 3.Apache/Nginx? 4.为何选择Php 5.4? 5.Phalcon还是其它? 6.MySql 5.6 / MariaDB ? 7.Cobar: ...

  6. C++指针例

    int num1=15;int num2=22; 状态一://const int *  不可以通过指针改变值,但是可以改变指向的变量//const int *p1=&num1;//std::c ...

  7. 向OC类中添加默认的协议实现(ProtocolKit)

    以forkingdog的PorotocolKit举例 举例 ProtocolKit Protocol extension for Objective-C Usage Your protocol: @p ...

  8. 解决vsftpd 2.2.2读取目录列表失败的问题

    该错误是由iptables的配置引起的,临时的解决方法是执行如下命令: [root@localhost soft]# modprobe ip_nat_ftp 再次登陆列表正常啦! 但当你重新启动服务器 ...

  9. Intel项目Java小记

    cannot be cast to javax.servlet.Filter添加provided即可 install -X是什么意思? Unsupported major.minor version ...

  10. BZOJ2191Splite

    Description 给两个多边形,问否在平移旋转不翻转不重叠的情况下拼成一个凸多边形. Input 每组第一行一个数N表示第一个多边形的顶点数,下接N行按顺序(逆/顺时针)给出顶点坐标,再下一行给 ...