app开发定制公司C/C++ 正则表达式 regex库介绍(详细版)

文章目录


前言

从C++11开始,C++app开发定制公司开始支持正则表达式的使用,app开发定制公司用于匹配字符串时非常方便!(app开发定制公司比如从爬取的网页源码app开发定制公司中提取指定的字符串app开发定制公司匹配用户输入邮箱是否app开发定制公司为正确格式app开发定制公司替换一篇文章中指定的app开发定制公司所有字符串

app开发定制公司但正如大家所看到的,C++app开发定制公司一如既往的使用模板实现,app开发定制公司以至于我们使用的时候,如果出错了,很难看明白到底哪里出错了

所以本文对C++正则表达式库进行详细解析,便于大家的使用!

一、总体观摩

正则表达式库为regex,使用C++11及以上即可正常使用

#include<regex>
  • 1

1.纵观所有类

regex文件里总共有7个模板类以及若干实例化的类

模板类实例化类用途
basic_regexregex:实际为basic_regex<char>,wregex:实际为basic_regex<wchar_t>,下面的类似,不再一一详细说明作为正则表达式对象,用于匹配文本
match_resultscmatchwcmatchsmatchwsmatch用于获得匹配到的结果,实际可以看作sub_match的数组
sub_matchcsub_match,wcsub_match ,ssub_match ,wssub_match保存捕获组,一般直接用match_result数组访问的方式直接调用,所以一般看不到它
regex_iteratorcregex_iterator,wcregex_iterator,sregex_iterator,wsregex_iterator用于遍历结果或子匹配的迭代器
regex_token_iteratorcregex_token_iteratorwcregex_token_iteratorsregex_token_iteratorwsregex_token_iterator用于遍历未匹配部分的迭代器
regex_error报告正则表达式库生成的错误
regex_traits描述用于匹配的元素的特征。一般用不上,有需求的可参考官方文档

虽然看着挺多,但其实平时真正用到的只有少数几个

特别需要注意的是,上面的类都是分类别配对使用的,比如:

regex ,cmatch,csub_match,cregex_iterator
  • 1

就是一组

或者

regex ,smatch,ssub_match,sregex_iterator
  • 1

也是一组

可以总结出的规律有:

  • 前缀没有w字母的为操作多字节字符,添加了w的则为操作宽字节字符
  • 前缀有c的,代表是操作char*类型字符串
  • 前缀有s的,代表是操作string类型字符串

注意,char*类型字符串与string类型实现类之间不能混用,否则会出错!

2.纵观所有函数

函数用途
regex_match匹配指定字符串整体是否符合
regex_search匹配字符串中符合的子字符串
regex_replace替换字符串中指定的字符串

二、使用详解

如何写正则表达式就不做细说,网上有很多教程,只对函数如何使用作出详细介绍

1.使用前需要了解的东西

下图为regex库默认使用的ECMAScript文法的表达式

如果想要更改为其它文法,只需要在regex构造函数中最后一位填入对应文法即可,例如:

regex r("<.*?>(.*)<.*?>", regex_constants::grep);
  • 1

当然除了选择文法,还可以选择其它标志,只需要将他们用符号 | 连接起来即可

如忽略大小写匹配可以写为

regex r("<.*?>(.*)<.*?>", regex_constants::grep|regex_constants::icase);
  • 1

可以看到,其实这些可选项都在regex_constants中,还有其它可选项如下:

不同文法之间的差异

还需要注意的是,C++中许多字符需要添加\ 符号进行转义才能使用,过于麻烦,所以C++11之后,出现了如下写法:

R"dem(内容)dem"
  • 1

使用该写法就可以不再转义即可使用,其中dem为任意字符,但要求前后一致即可,其它为固定写法

2.测试字符串

该功能用到regex_match 函数

一般来说,最常用的就是下面这种写法:

比如测试用户输入字符串是否包含@符号:

regex r(".*@.*");string str;cin >> str;if (regex_match(str, r)) {	cout << "匹配成功";}else {	cout << "匹配失败";}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3.搜索子字符串

该功能用到regex_search函数

一般用法肯定是找出一段文本中所需要的子字符串,用法如下

		string sStr; //要进行匹配的字符串		std::string::const_iterator begin = sStr.begin(); //开始迭代器		std::string::const_iterator end = sStr.end(); //结束迭代器		std::smatch m; //匹配的结果		regex r; //正则表达式		while (std::regex_search(begin, end, m, r)) {			begin = m[0].second; //更新开始迭代器的位置			m[n].str(); //获得第n个捕获组,其中0表示匹配到的全部子字符串		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

该代码段就是不断从sStr中匹配符合r的子字符串,匹配成功则返回true,并将匹配到的结果放在m中,可通过m[n].str()方式返回指定捕获组的子字符串

同时m[0].second记录了当前匹配到的位置,所以通过它更新begin ,就可以遍历所有子字符串,直到无法匹配,返回false,结束

4.使用迭代器

如果你认为regex_search用起来比较麻烦,则可以使用迭代器,用法如下:

	regex r("-(.*?)-");	string s = "yushi-csdn--yushi-csdn";	sregex_iterator beg(s.begin(),s.end(),r);	sregex_iterator end;	for (; beg != end; beg++) {		cout << beg->str(1) << endl;	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

由于sregex_iterator 默认构造函数为指向最后一个元素之后,所以对end没有进行任何处理,只是作为一个结束标志

成员函数str可以返回指定捕获组的字符串,不传入数字则代表全部匹配内容

5.替换字符串

该功能用到regex_replace函数

string sStr; //要进行匹配的源字符串regex r; //正则表达式string toReplace; //进行替换的字符串string ret=regex_replace(sStr, r, toReplace)
  • 1
  • 2
  • 3
  • 4

该函数就是将sStr中匹配符合r的子字符串,将其全部替换为toReplace,并将结果返回到ret中

小技巧:可以在toReplace添加$n,n代表着第几个捕获组,可用于格式化字符串,总结如下:

6.分割字符串

这里主要使用到了sregex_token_iterator

	regex r("-"); //以-为分隔符	string s = "yushi-csdn-yushi-csdn";	sregex_token_iterator beg(s.begin(), s.end(), r,-1); //传入-1,代表对匹配到的分隔符之间的内容感兴趣	sregex_token_iterator end; //结束标志	for (; beg != end; beg++) {		cout << beg->str() << endl;	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

用法基本于上述迭代器用法一样

唯一需要注意的是最后传入的那个-1,代表着我想要的是匹配项之间的内容

7.异常处理

regex库里已经实现了异常类regex_error ,直接使用即可,what函数将返回错误信息

	try	{		regex r("\{\}");	}	catch (const std::regex_error & e)	{		cout << e.what()<<endl;	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

上述正则表达式使用grep语法,将{}进行转义,将输出以下错误:

regex_error(error_badrepeat): One of *?+{ was not preceded by a valid regular expression.
  • 1

三、封装成类

可以看出来,原库函数使用起来很不方便,所以我花了点时间将上述几种常用功能封装成类,方便使用

#include<regex>#include<list>#include<string>class SRegex {private:	std::regex r;	std::wregex wr;	SRegex(const SRegex& r) = delete;public:	SRegex() {}	/**	 * @brief 多字节字符构造函数	 * @param pattern 匹配模式	*/	SRegex(const std::string& pattern) {		r = pattern;	}	/**	* @brief 宽字节字符构造函数	* @param pattern 匹配模式	*/	SRegex(const std::wstring& pattern) {		wr = pattern;	}	/**	 * @brief (多字节)重新设置匹配模式	 * @param pattern 匹配模式	*/	void SetPattern(const std::string& pattern) {		r = pattern;	}	/**	* @brief (宽字节)重新设置匹配模式	* @param pattern 匹配模式	*/	void SetPattern(const std::wstring& pattern) {		wr = pattern;	}	/**	 * @brief 测试源字符串是否满足匹配模式(多字符)	 * @param sStr 源字符串	 * @return 匹配返回true,否则返回false	*/	bool IsMatch(const std::string& sStr) {		return std::regex_match(sStr, r);	}	/**	* @brief 测试源字符串是否满足匹配模式(宽字符)	* @param sWStr 源字符串	* @return 匹配返回true,否则返回false	*/	bool IsMatch(const std::wstring& swStr) {		return std::regex_match(swStr, wr);	}	/**	 * @brief 获得所有满足匹配模式的子字符串(多字节字符)	 * @param res 获得匹配到的结果	 * @param sStr 源字符串	 * @param index 获取指定捕获组,默认为0,即全部	 * @return 存在返回true,否则返回false	*/	bool GetSubStr(std::list<std::string>& res, const std::string& sStr, int index = 0) {		res.clear();		std::string::const_iterator begin = sStr.begin();		std::string::const_iterator end = sStr.end();		std::smatch m;		while (std::regex_search(begin, end, m, r)) {			begin = m[0].second;			res.push_back(std::move(m[index].str()));		}		return !res.empty();	}	/**	 * @brief 获得所有满足匹配模式的子字符串(宽字符)	 * @param res 获得匹配到的结果	 * @param sStr 源字符串	 * @param index 获取指定捕获组,默认为0,即全部	 * @return 存在返回true,否则返回false	*/	bool GetSubStr(std::list<std::wstring>& res, const std::wstring& sStr, int index = 0) {		res.clear();		std::wstring::const_iterator begin = sStr.begin();		std::wstring::const_iterator end = sStr.end();		std::wsmatch m;		while (std::regex_search(begin, end, m, wr)) {			res.push_back(std::move(m[index].str()));		}		return !res.empty();	}	/**	 * @brief 特换匹配到的子字符串(多字节)	 * @param sStr 源字符串	 * @param toReplace 将要进行替换的字符串	 * @return 返回替换成功的字符串	*/	std::string Replace(const std::string& sStr, const std::string& toReplace) {		return std::move(std::regex_replace(sStr, r, toReplace));	}	/**	 * @brief 特换匹配到的子字符串(宽字节)	 * @param sStr 源字符串	 * @param toReplace 将要进行替换的字符串	 * @return 返回替换成功的字符串	*/	std::wstring Replace(const std::wstring& sStr, const std::wstring& toReplace) {		return std::move(std::regex_replace(sStr, wr, toReplace));	}	/**	 * @brief 分割字符串(多字节)	 * @param sStr 需要进行分割的源字符串	 * @return 返回分割后的字符串链表	*/	std::list<std::string> Split(const std::string& sStr) {		std::sregex_token_iterator beg(sStr.begin(), sStr.end(), r, -1);		std::sregex_token_iterator end;		std::list<std::string> res;		for (; beg != end; beg++) {			res.push_back(std::move(beg->str()));		}		return std::move(res);	}	/**	 * @brief 分割字符串(宽字节节)	 * @param sStr 需要进行分割的源字符串	 * @return 返回分割后的字符串链表	*/	std::list<std::wstring> Split(const std::wstring& sStr) {		std::wsregex_token_iterator beg(sStr.begin(), sStr.end(), wr, -1);		std::wsregex_token_iterator end;		std::list<std::wstring> res;		for (; beg != end; beg++) {			res.push_back(std::move(beg->str()));		}		return std::move(res);	}};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137

因为我测试数据不多,可能存在bug,欢迎在评论区指出,我会及时更正,

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发