理解C++11正则表达式(2)

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

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

正文 

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

 ECMAScript,spa

 basic(POSIX Basic Regular Expressions),翻译

   extended(POSIX Extended Regular Expressions ),3d

   awk(POSIX awk) ,c++11

   grep(POSIX grep ),blog

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

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

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

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

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

二、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标准库。

相关文章
相关标签/搜索