Cpp标准库之 std::regex 类的使用

一、简介:

        本文主要是大致的介绍如何使用 C++ 标准库中 std::regex 相关类库,用来打发下无聊的时间。

        在使用 C++ 标准库正则表达式之前,肯定是要先学习正则表达式语法的,不解释。

        要学习正则表达式语法,你百度一下,可以百度一把大。但是,我个人觉得写的最经典的莫过于这篇文章了 正则表达式30分钟入门教程 ,感谢这篇文章作者 30 秒。我觉得只需要读懂这篇文章的 80%,你将感受到正则表达式处理字符串那毁天灭地的威力。


二、常用 C++ 标准库正则表达式类:

        C++ 标准库中常用正则表达式类主要包含如下 5 组:


        有了以上 5 组模板,基本上可以处理所有的字符串处理需求了。


三、C++ 正则表达式模板的使用:

        std::regex_match: 正则表达式需要匹配整个字符串序列,也就是说正则表达式要与字符串完全匹配。因此,它是单次匹配,否则匹配失败。

        范例代码如下:

void match()
{
	/
	//std::regex_match
	//std::regex_match: 正则表达式需要匹配整个字符串序列, 也就是说正则表达式要与
	//字符串完全匹配, 因此, 它是单次匹配, 否则匹配失败. 
	//此外, 它还可以获取子匹配的组

	std::string text = "Date:2017-10-10";

	//构造正则表达式
	//这里 "()" 用于捕获组, 捕获组的编号是按照 "(" 出现的顺序, 从左到右, 从1开始进行编号的 
	std::string pattern = "Date.(\\d{4})-(\\d{2}-(\\d{2}))";
	std::regex express(pattern);

	//匹配
	std::cout.setf(std::ios_base::boolalpha);
	/*模板函数1-1*/
	//第0组一般是整个正则表达式匹配结果, 其他依次是捕获组的结果
	//这里使用的是 std::string::iterator 迭代器, 与 begin()/ end() 返回的迭代器类型(std::string::iterator)要一致
	std::match_results<std::string::iterator> results1;
	if(std::regex_match(text.begin(), text.end(), results1, express))
	{
		std::match_results<std::string::iterator>::const_iterator iter;
		for (iter = results1.begin(); iter != results1.end(); iter++)
		{
			std::cout << iter->length() << ": " << iter->str() << std::endl;
		}
	}
	/*输出
	15: Date:2017-10-10
	4: 2017
	5: 10-10
	2: 10
	*/

	/*模板函数1-2*/
	//第0组一般是整个正则表达式匹配结果, 其他依次是捕获组的结果
	//std::smatch == std::match_results<std::string::const_iterator>
	std::smatch s_results1;
	if(std::regex_match(text.cbegin(), text.cend(), s_results1, express))
	{
		std::match_results<std::string::const_iterator>::const_iterator iter;
		for (iter = s_results1.begin(); iter != s_results1.end(); iter++)
		{
			std::cout << iter->length() << ": " << iter->str() << std::endl;
		}
	}
	/*输出
	15: Date:2017-10-10
	4: 2017
	5: 10-10
	2: 10
	*/

	/*模板函数2*/
	//显示字符串是否符合正则表达式, 用于检测字符串规则
	std::cout << std::regex_match(text.begin(), text.end(), express) << std::endl;

	/*模板函数3*/
	//第0组一般是整个正则表达式匹配结果, 其他依次是捕获组的结果
	//std::cmatch == std::match_results<const char*>
	std::cmatch c_results3;
	if(std::regex_match(text.c_str(), c_results3, express))
	{
		for (auto iter = c_results3.begin(); iter != c_results3.end(); iter++)
		{
			std::cout << iter->length() << ": " << iter->str() << std::endl;
		}
	}
	/*输出
	15: Date:2017-10-10
	4: 2017
	5: 10-10
	2: 10
	*/

	/*模板函数4*/
	//显示字符串是否符合正则表达式, 用于检测字符串规则
	std::cout << std::regex_match(text.c_str(), express) << std::endl;

	/*模板函数5*/
	//第0组一般是整个正则表达式匹配结果, 其他依次是捕获组的结果
	std::match_results<std::string::const_iterator> s_results5;
	if(std::regex_match(text, s_results5, express))
	{
		for (size_t index = 0; index < s_results5.size(); index++)
		{
			//sub_match: 子匹配, match_results里面都存放的是sub_match
			//sub_match 可以理解为 std::pair 的扩展, 它继承了 std::pair,
			//其中 first 实际上存放的是获取的字符串头指针地址, second 为尾指针地址
			std::ssub_match sub = s_results5[index];
			std::cout << sub.length() << ": " << sub.str() << std::endl;
		}
	}
	/*输出
	15: Date:2017-10-10
	4: 2017
	5: 10-10
	2: 10
	*/

	/*模板函数6*/
	//显示字符串是否符合正则表达式, 用于检测字符串规则
	std::cout << std::regex_match(text, express) << std::endl;
	/
}

        std::regex_search: 搜素正则表达式参数,但它不要求整个字符序列完全匹配。而且它只进行单次搜索,搜索到即停止继续搜索,不进行重复多次搜索。

        范例代码如下:

void search()
{
	/
	//std::regex_search
	//std::regex_search: 搜素正则表达式参数, 但它不要求整个字符序列完全匹配. 
	//而且它只进行单次搜索, 搜索到即停止继续搜索, 不进行重复多次搜索.

	std::string text = "Date:2017-10-10 ~ 2017-10-15";

	//构造正则表达式
	//这里 "()" 用于捕获组, 捕获组的编号是按照 "(" 出现的顺序, 从左到右, 从1开始进行编号的
	std::string pattern = "(\\d{4})-(\\d{2}-(\\d{2}))";
	std::regex express(pattern);

	//匹配
	std::cout.setf(std::ios_base::boolalpha);

	/*模板函数1*/
	//第0组一般是整个正则表达式匹配结果, 其他依次是捕获组的结果, 它不进行重复多次搜索
	std::match_results<std::string::iterator> results1;
	if(std::regex_search(text.begin(), text.end(), results1, express))
	{
		//使用迭代器遍历, 这里的迭代器实际上是指向 std::sub_match 的指针
		std::match_results<std::string::iterator>::const_iterator iter;
		for (iter = results1.begin(); iter != results1.end(); iter++)
		{
			std::cout << iter->length() << ": " << iter->str() << std::endl;
		}
	}
	/*输出
	10: 2017-10-10
	4: 2017
	5: 10-10
	2: 10
	*/
	
	/*模板函数2*/
	//显示是否有搜索到符合正则表达式的结果
	std::cout << std::regex_search(text.begin(), text.end(), express) << std::endl;

	/*模板函数3*/
	//第0组一般是整个正则表达式匹配结果, 其他依次是捕获组的结果, 它不进行重复多次搜索
	std::cmatch c_results3;
	if(std::regex_search(text.c_str(), c_results3, express))
	{
		for (size_t index = 0; index < c_results3.size(); index++)
		{
			//获取组里面的数据, 注意: 这里使用的是 std::csub_match, 
			//实际上存放在 std::match_results 里面的数据就是一组 std::sub_match
			std::csub_match sub = c_results3[index];

			//先获取长度, 再获取内容
			std::cout << sub.length() << ": " << sub.str() << std::endl; 
		}
	}
	/*输出
	10: 2017-10-10
	4: 2017
	5: 10-10
	2: 10
	*/

	/*模板函数4*/
	//显示是否有搜索到符合正则表达式的结果
	std::cout << std::regex_search(text.c_str(), express) << std::endl;

	/*模板函数5*/
	//第0组一般是整个正则表达式匹配结果, 其他依次是捕获组的结果, 它不进行重复多次搜索
	std::smatch s_results5;
	if (std::regex_search(text, s_results5, express))
	{
		for (auto iter = s_results5.begin(); iter != s_results5.end(); iter++)
		{
			std::cout << iter->length() << ": " << iter->str() << std::endl;
		}
	}
	/*输出
	10: 2017-10-10
	4: 2017
	5: 10-10
	2: 10
	*/

	/*模板函数6*/
	//显示是否有搜索到符合正则表达式的结果
	std::cout << std::regex_search(text, express) << std::endl;
}

        std::regex_replace: 多次搜索整个正则表达式(不考虑捕获组),然后替换正则表达式匹配到的结果。

        范例代码如下:

void replace()
{
	/
	//std::regex_replace
	//std::regex_replace: 

	std::string text = "Date:2017-10-10 ~ 2017-10-15";

	//构造正则表达式
	//这里 "()" 用于捕获组, 捕获组的编号是按照 "(" 出现的顺序, 从左到右, 从1开始进行编号的 
	std::string pattern = "(\\d{4})-(\\d{2}-(\\d{2}))";
	std::regex express(pattern);

	//定义存储结果变量已经替换字符
	std::string result(256, '0');
	std::string substitutes = "2017-10-12";

	/*模板函数1*/
	//多次搜索整个正则表达式(不考虑捕获组), 然后替换正则表达式匹配到的结果 
	//std::regex_replace 模板函数返回值实际上是新的字符串存入变量后尾部的指针位置, 置 0 是为了防止变量数据出错或乱码
	*std::regex_replace(result.begin(), text.begin(), text.end(), express, substitutes) = '\0';
	std::cout << result.c_str() << std::endl;
	/*输出:
	Date:2017-10-12 ~ 2017-10-12
	*/
	
	result.clear();
	result.resize(256, '0');

	/*模板函数2*/
	//多次搜索整个正则表达式(不考虑捕获组), 然后替换正则表达式匹配到的结果 
	//std::regex_replace 模板函数返回值实际上是新的字符串存入变量后尾部的指针位置, 置 0 是为了防止变量数据出错或乱码
	result = std::regex_replace(text, express, substitutes);
	std::cout << result.c_str() << std::endl;
	/*输出:
	Date:2017-10-12 ~ 2017-10-12
	*/
}

        std::regex_iterator: 用于多次重复匹配,不分组,只进行多次匹配整个正则表达式,可获取整个正则表达式的结果。

        范例代码如下:

void iterator()
{
	/
	//std::regex_iterator
	//std::regex_iterator: 用于多次重复匹配, 不分组, 只进行多次匹配整个正则表达式,
	//可获取整个正则表达式的结果

	std::string text = "Date:2017-10-10 ~ 2017-10-15";

	//构造正则表达式
	//这里 "()" 用于捕获组, 捕获组的编号是按照 "(" 出现的顺序, 从左到右, 从1开始进行编号的
	std::string pattern = "(\\d{4})-(\\d{2}-(\\d{2}))";
	std::regex express(pattern);

	std::regex_iterator<std::string::const_iterator> begin(text.cbegin(), text.cend(), express);
	//std::sregex_iterator == std::regex_iterator<std::string::const_iterator>
	for (auto iter = begin; iter != std::sregex_iterator(); iter++)
	{
		std::cout << iter->length() << ": " << iter->str() << std::endl;
	}
	/*输出
	10: 2017-10-10
	10: 2017-10-15
	*/
}

        std::regex_token_iterator: 用于多次匹配正则表达式, 它可以获取整个正则表达式的结果,也可以获取正则表达式的前缀,还可以获取正则表达式的分组子匹配。

        范例代码如下:

void token_iterator()
{
	/
	//std::regex_token_iterator
	//std::regex_token_iterator: 用于多次匹配正则表达式, 它可以获取整个正则表达式
	//的结果, 也可以获取正则表达式的前缀, 还可以获取正则表达式的分组子匹配

	std::string text = "Date:2017-10-10 ~ 2017-10-15";

	//构造正则表达式
	//这里 "()" 用于捕获组, 捕获组的编号是按照 "(" 出现的顺序, 从左到右, 从1开始进行编号的
	std::string pattern = "(\\d{4})-(\\d{2}-(\\d{2}))";
	std::regex express(pattern);

	/*构造函数2-1*/
	//(多次匹配)显示正则表达式匹配, 即参数 4 等于 0
	std::regex_token_iterator<std::string::const_iterator> begin2_1(text.cbegin(), text.cend(), express);
	//std::sregex_token_iterator == std::regex_token_iterator<std::string::const_iterator>
	for (auto iter = begin2_1; iter != std::sregex_token_iterator(); iter++)
	{
		std::cout << iter->length() << ": " << iter->str() << std::endl;
	}
	/*输出
	10: 2017-10-10
	10: 2017-10-15
	*/

	/*构造函数2-2*/
	//(多次匹配)显示正则表达式匹配到的前缀, -1 则表示只显示前缀
	std::regex_token_iterator<std::string::const_iterator> begin2_2(text.cbegin(), text.cend(), express, -1);
	for (auto iter = begin2_2; iter != std::sregex_token_iterator(); iter++)
	{
		std::cout << iter->length() << ": " << iter->str() << std::endl;
	}
	/*输出
	5: Date:
	3:  ~
	*/

	/*构造函数2-3*/
	//(多次匹配)显示正则表达式子匹配, 3 表示第三组子匹配
	std::regex_token_iterator<std::string::const_iterator> begin2_3(text.cbegin(), text.cend(), express, 3);
	for (auto iter = begin2_3; iter != std::sregex_token_iterator(); iter++)
	{
		std::cout << iter->length() << ": " << iter->str() << std::endl;
	}
	/*输出
	2: 10
	2: 15
	*/

	/*构造函数3*/
	//(多次匹配)显示正则表达式匹配到的前缀和子匹配, -1 表示前缀, 2 表示第二个子匹配
	std::vector<int> vec;
	vec.push_back(-1);
	vec.push_back(2);
	std::regex_token_iterator<std::string::iterator> begin3(text.begin(), text.end(), express, vec);
	for (auto iter = begin3; iter != std::regex_token_iterator<std::string::iterator>(); iter++)
	{
		std::cout << iter->length() << ": " << iter->str() << std::endl;
	}
	/*输出
	5: Date:
	5: 10-10
	3:  ~
	5: 10-15
	*/

	/*构造函数4*/
	//(多次匹配)显示正则表达式匹配到的前缀和整个正则表达式匹配, -1 表示前缀, 0 表示匹配整个正则表达式.
	int arr[] = {-1, 0};
	std::regex_token_iterator<std::string::iterator> begin4(text.begin(), text.end(), express, arr);
	for (auto iter = begin4; iter != std::regex_token_iterator<std::string::iterator>(); iter++)
	{
		std::cout << iter->length() << ": " << iter->str() << std::endl;
	}
	/*输出
	5: Date:
	10: 2017-10-10
	3:  ~
	10: 2017-10-15
	*/
}

        主函数:

int main()
{
	search();

	system("pause");
	return 0;
}

        以上范例及说明基本上已介绍模板的使用方法,其中模板中的 match_flag_type 我没有使用,可以查阅 MSDN 来使用。另,源代码下载地址:std::regex usge demo



  • 25
    点赞
  • 116
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

l357630798

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值