C++ regex库常用函数及实例

简介

regex是C++标准库中用于正则表达式(regular expression)的部分。

大致有如下常用组件:

组件名称 作用
regex 表示有一个正则表达式的类
regex_match 将一个字符序列与一个正则表达式匹配
regex_search 寻找第一个与正则表达式匹配的子序列
regex_replace 使用给定格式替换一个正则表达式
sregex_iterator 迭代器适配器,内部调用regex_search来遍历一个string中所有匹配的子串
smatch 容器类,保存在string中搜索的结果
ssub_match string中匹配的子表达式的结果
示例

在下面一个简单的例子里使用一些组件

#include<regex>
#include<iostream>
using namespace std;
//正则表达式
void main()
{
	string pattern = "^([a-z]|_)[[:alnum:]]+";
    //开头的^表示从字符串开头开始匹配,|表示或,alnum表示字母或数字,+表示至少重复一次
	regex r(pattern, regex::icase);//初始化正则表达式类,icase表示忽略大小写
	string s("Asff");
	smatch results;//用于保存成功匹配的相关信息
	if (regex_search(s, results, r))
		cout << results.str() << endl;
	s="_qwer";
	if (regex_search(s, results, r))
		cout << results.str() << endl;
	s="9sff";
	if (regex_search(s, results, r))
		cout << results.str() << endl;
}

输出如下:

Asff
_qwer

​ 在这个例子里,我们通过regex_search函数,查找第一个与正则表达式匹配的子序列,smatch对象将会保存匹配结果的相关细节。

异常

​ C++的正则表达式并不是由C++编译器解析,而是在运行时由相关库函数进行解析,因此如果正则表达式存在语法错误,程序将会抛出名为regex_error的异常。

捕获异常并且输出错误信息:

void fun()
{
    try{
    	regex r("([[:alpha:]]");        
    }catch(regex_error e)
    {
        cout<<e.what()<<"\n";//错误信息
        cout<<e.code()<<endl;//错误码
	}
}
char数组传参

​ regex_search函数的输入序列参数可以传入string或者以'\0'结尾的字符数组,传入string时,使用smatch对象接受匹配成功的相关信息;而传入char*时,如果还使用smatch对象就会编译失败,此时需要使用cmatch对象才能编译成功。

使用regex迭代器来获取所有匹配

sregex_iterator的部分操作如下表

操作 作用
sregex_iterator it(b,e,r); b,e分别为输入序列的迭代器起始尾后位置,将sregex_iterator对象it定位到输入中第一个匹配的位置
sregex_iterator it_end; 无参构造函数生成尾后迭代器
*it 解引用,根据最后一个调用regex_search的结果,返回一个smatch对象的引用
it-> 间接引用smatch的成员函数
++it 在当前匹配位置调用regex_search,并返回递增后的迭代器
it++ 在当前匹配位置调用regex_search,但返回递增前的迭代器
it1==it2 如果都是尾后迭代器,则相等。非尾后迭代器如果由相同的输入序列和相同的regex对象构造,则相等
it1!=it2 不符合相等的情况
综合示例

​ 综合上面的知识,我们可以编写一个提取合法ipv4地址的小程序,其中regex对象pattern中使用\\的原因是:一个\用于转义'('、')'、'd'(表示整数)等符号,另一个是由于C++中\为转义字符,\\才表示一个\符号。

#include<regex>
#include<iostream>
using namespace std;

bool validSubExepression(const smatch& s)
{//检查表达式是否合法
	if (s[1].matched)//如果有左括号,那么要求一定要有匹配的右括号
		return s[9].matched && s[3].str() == s[5].str() && s[5].str() == s[7].str();//且3个分隔符要相同
	else//如果没有左括号,那么要求没有右括号
		return !s[9].matched && s[3].str() == s[5].str() && s[5].str() == s[7].str();
}

bool overflow(const smatch& s)
{//ip地址是否溢出
	for (int i = 2; i <= 8; i++)
	{
		int number = atoi(s.str().c_str());
		if (number > 255)
			return true;
	}
	return false;
}

int main()
{
	string pattern =
		"(\\()?(\\d{1,3})([-. ])?(\\d{1,3})([-. ])?(\\d{1,3})([-. ])?(\\d{1,3})(\\))?";
	string ipaddress = "192.168.1.2 (123.233.111.33 114.114.114.114) (8-8.8.8) 7-8-9-10 172 0 0 1 888.224.525.244 192&168&1&1";
	string fmt = "($2.$4.$6.$8)";//格式化,子表达式2,4,6,8原样输出,其余部分按(...)格式输出
	try
	{
		regex r(pattern);
		for (sregex_iterator it(ipaddress.begin(), ipaddress.end(), r), end_it; it != end_it; ++it)
		{
			if (!overflow(*it))
			{
				if (validSubExepression(*it))
				{
					cout << "Before format:" << it->str() << endl;
					cout << "After  format:" << regex_replace(it->str(), r, fmt) << endl << endl;
				}
				else
				{
					cout << "not valid:" << endl;
					cout << "Before format:" << it->str() << endl;
					cout << "After  format:" << regex_replace(it->str(), r, fmt) << endl << endl;
				}
			}
			else
				cout << "overflow" << endl;
		}
	}
	catch (regex_error e)
	{
		cout << "(error code:" << e.code() << ")" << endl;//输出错误代码
		cout << e.what() << endl;                         //输出错误信息
	}
}
posted @ 2020-10-10 19:26  shadowgully  阅读(3602)  评论(0编辑  收藏  举报