代码改变世界

C++正则表达式

2015-08-24 00:38  rangers  阅读(5220)  评论(0编辑  收藏  举报

正则表达式是处理文本强有力的工具,它使用一套复杂且完善的语法规则,能够解决文本处理领域的绝大多数问题,诸如验证、匹配、查找、替换等等,而这些问题用通常的字符串算法是很难解决的。

C++11正式加入了regex库,下面通过几个简单的例子介绍一下regex库的使用。
有关正则表达式的语法知识,参考这里

要使用regex库,要包含头文件#include <regex>

类摘要

basic_regex

template<class _Elem,
	class _RxTraits = regex_traits<_Elem> >
	class basic_regex
		: public _Regex_base
	{	//
...
typedef basic_regex<char> regex;
typedef basic_regex<wchar_t> wregex;

该类封装了正则表达式的解析和编译,是正则表达式的基本类。一般有两种特化regexwregex分别对应窄字符和宽字符。
构造一个正则表达式很简单:

string regex_str("^(\\d{6})((1|2)\\d{3})((0|1)\\d)([0-3]\\d)(\\d{3}(X|\\d))$");
std::regex pattern(regex_str,std::regex::icase);

match_results
该类保存了正则表达式匹配的结果。match_results为正则表达式的匹配结果提供了一个类似容器的视图,可以用size()和empty()判断匹配结果中子表达式的数量,operator[]返回低i个子表达式。如果i==0,则返回整个表达式的匹配对象。
match_results有以下特化方式:

typedef match_results<const char *> cmatch;
typedef match_results<const wchar_t *> wcmatch;
typedef match_results<string::const_iterator> smatch;
typedef match_results<wstring::const_iterator> wsmatch;  

sub_match
该模板类是一个类似迭代器的对象,继承自std::pair,用来表示一个与子表达式匹配的序列,可以把它当作一个字符区间。

正则匹配
自由函数regex_match()用来检查一个字符串是否完全匹配一个正则表达式,返回bool结果。

//匹配身份证号码
// ^\d{6}(1|2)\d{3}(0|1)\d[0-3]\d\d{3}(X|\d)$
string regex_str("^(\\d{6})((1|2)\\d{3})((0|1)\\d)([0-3]\\d)(\\d{3}(X|\\d))$");
std::regex pattern(regex_str,std::regex::icase);//忽略字母大小写

string id("61251719901212444X");
assert(std::regex_match(id,pattern) == true);

// [a-zA-Z0-9_-]+@[a-zA-Z0-9]+\.[a-zA-Z0-9]+  邮箱简单正则
string mail_reg_str("^[a-zA-Z0-9_-]+@[a-zA-Z0-9]+\\.[a-zA-Z0-9]+$");
std::regex mail_reg(mail_reg_str,std::regex::icase);

assert(std::regex_match("chm--1989@163.com",mail_reg) == true);

使用正则匹配结果
使用match_results来提取匹配结果。

void IPTest()
{
	//识别一个IP地址,并打印各个部分
	//输入exit退出程序
	bool isInputEnd = false;
	//(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})
	//有四个子表达式,括号中的内容为一个子表达式
	std::regex ip_reg("(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})");
	std::smatch matchResult;
	const string exitStr("EXIT");
	while (!isInputEnd)
	{
		cout << "\nInput a IP address:";
		string inputStr;
		std::getline(std::cin,inputStr);
		if (inputStr.empty())
		{
			continue;
		}
		
		string tmpStr(inputStr);
		std::transform(tmpStr.begin(),tmpStr.end(),tmpStr.begin(),toupper);
		if (tmpStr == exitStr)
		{
			cout << "\nSYSTEM EXIT!";
			isInputEnd = true;
			continue;
		}
		//正则匹配
		if (std::regex_match(inputStr,matchResult,ip_reg))
		{
			cout << "Match: ";
			//打印子表达式结果
			for (size_t i = 1; i < matchResult.size(); ++i)
			{
				cout << matchResult[i] << " ";
			}
		}
		else
		{
			cout << "Not Match!";
		}
		
	}
}

运行如下:
reg_ip

正则查找
regex_search()regex_match的区别是:regex_match要求输入的字符串必须要与正则表达式完全匹配,而regex_search则检测输入表达式中是否包含正则表达式,即存在一个匹配正则表达式的子串。

//搜索输入字符串中所有满足正则表达式 \d{3} 的子串
std::regex reg2("\\d{3}");
string test_str("abc12312a--1b234-7890abc567");
string::const_iterator iter = test_str.begin();
string::const_iterator iterEnd = test_str.end();
std::smatch match_result;
cout << "\n\n" << test_str;
while (std::regex_search(iter,iterEnd,match_result,reg2))
{
	cout << "\nMatch: " << match_result[0];
	iter = match_result[0].second; //更新搜索起始位置
}

正则替换
regex_repalce

template<class _RxTraits,
	class _Elem>
	_STD basic_string<_Elem> regex_replace(
		const _STD basic_string<_Elem>& _Str,
		const basic_regex<_Elem, _RxTraits>& _Re,
		const _STD basic_string<_Elem>& _Fmt,
		regex_constants::match_flag_type _Flgs =
			regex_constants::match_default)
	{	// search and replace
...

regex_replace 在整个字符序列中查找正则表达式e的所有匹配。这个算法每次成功匹配后,就根据参数fmt对匹配字符串进行格式化。

//使用regex_replace 实现trim功能,去掉字符串前后的空白字符
std::regex reg1("^(\\s)*");
std::regex reg2("\\s*$");

string test_str("  abc  \t");
string t("");
test_str = std::regex_replace(test_str,reg1,t);	//trim_left
test_str = std::regex_replace(test_str,reg2,t); //trim_right

测试结果如下:
regex_repalce_png