本文主要参考为《C++Primer第五版》
0.常用正则表达式
中文字符:[\u4e00-\u9fa5]
双字节字符(包括汉字在内):[^\x00-\xff]
空白符:\n\s*\r
Email地址:[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?
网址URL:[a-zA-z]+://[^\s]*
国内电话号码:\d{3}-\d{8}|\d{4}-\{7,8}
腾讯qq:[1-9][0-9]{4,}
中国邮政编码:[1-9]\d{5}(?!\d)
18位身份证号:^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$
(年-月-日)格式日期:([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8])))
正整数:^[1-9]\d*$
负整数:^-[1-9]\d*$
整数:^-?[1-9]\d*$
非负整数:^[1-9]\d*|0$
非正整数:^-[1-9]\d*|0$
正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$
负浮点数:^-[1-9]\d*\.\d*|-0\.\d*[1-9]\d*$
正则表达式在线测试:http://tool.oschina.net/regex
1、概述
这里主要介绍的是C++正则表达式库(
RE库),RE库定义在头文件regex中,包含多个组件。
简要介绍如下:
regex 表示有一个正则表达式的类
regex_match 将一个字符序列与一个正则表达式匹配
regex_search 寻找第一个与正则表达式匹配的子序列
regex_replace 使用给定格式替换一个正则表达式
sregex_iterator 迭代器适配器,调用regex_search来遍历一个string中所有匹配的子串
smatch 容器类,保存在string中的搜索的结果
ssub_match string中匹配的子表达式的结果
2、实例1--查找违反规则的单词
规则:i在e之前,除非在c之后。
2.1 使用
regex_search
--
只输出
第一个匹配结果
#include <iostream>
#include <string>
#include <regex>
using namespace std;
int main()
{
//构造正则表达式
string re("[A-Za-z]*[^c]ei[A-Za-z]*");
//C++regex的写法
//string re("[[:alpha:]]*[^c]ei[[:alpha:]]*");
regex r(re, regex::icase);
//输入
string file("receipt freind theif receive");
//定义一个对象保存搜索结果
smatch results;
if (regex_search(file, results, r))
cout << results.str() << endl;
return 0;
}
2.2 使用
sregex_iterator
--
输出所有
匹配结果
在for循环中,当我们定义it时,sregex_iterator的构造函数调用regex_serch将
it定位到输入中第一个与r匹配的位置,而end_it是一个空sregex_iterator,
起到尾后迭代器的作用。
程序源代码如下:
#include <iostream>
#include <string>
#include <regex>
using namespace std;
int main()
{
//构造正则表达式
string re("[A-Za-z]*[^c]ei[A-Za-z]*");
//C++regex的写法
//string re("[[:alpha:]]*[^c]ei[[:alpha:]]*");
regex r(re, regex::icase);
//输入
string file("receipt freind theif receive");
//它将反复调用regex_search来寻找文件中的所有匹配
for (sregex_iterator it(file.begin(), file.end(), r), end_it; it != end_it; ++it)
cout << it->str() << endl;
return 0;
}
2.3
输出匹配结果的上下文
匹配结果
smatch中有两个名为
prefix和
suffix的成员,分别返回表示输入序列中当前匹配之前和之后部分的
ssub_match对象。
程序源代码如下:
#include <iostream>
#include <string>
#include <regex>
using namespace std;
int main()
{
//构造正则表达式
string pattern("[[:alpha:]]*[^c]ei[[:alpha:]]*");
regex r(pattern, regex::icase);
//输入
string file("receipt freind theif receive");
//它将反复调用regex_search来寻找文件中的所有匹配
for (sregex_iterator it(file.begin(), file.end(), r), end_it; it != end_it; ++it)
{
//前缀的大小
auto pos = it->prefix().length();
//上下文最多40个字符
pos = pos > 40 ? pos - 40 : 0;
cout << it->prefix().str().substr(pos) //前缀
<< "\n\t\t>>>" << it->str() << "<<<\n" //匹配的单词
<< it->suffix().str().substr(0, 40) //后缀
<< endl;
}
return 0;
}
3.实例2--匹配电话号码(有多种格式)
3.1
子表达式
这里要使用正则表达式中的
子表达式,正则表达式语法通常
用括号表示子表达式。
举例:
regex r("([[:alnum:]]+)\\.(cpp|cxx|cc)$");
包含两个子表达式:
- ([[:alnum:]]+),匹配一个或多个字符的序列
- (cpp|cxx|cc)$"),匹配文件扩展名
如下代码就可以只输出文件名,而不输出后缀:
if (regex_search(filename, results, r))
cout << results.str(1) << endl
第一个子匹配
位置为0,
表示整个模式对应的匹配,随后是每个
子表达式对应的匹配。
例如,如果文件名为foo.cpp,则results.str(0)将保存foo.cpp;results.str(1)将保存foo;而results.str(2)将保存cpp。
3.2 使用子表达式进行数据验证
整个正则表达式包含七个子表达式:(ddd)分隔符ddd分隔符dddd
子表达式1、3、4和6是可选的;2、5和7保存号码
"(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ])?(\\d{4})";
1.(\\()?表示区号部分可选的左括号
2.(\\d{3})表示区号
3.(\\))表示区号部分可选的右括号
4.([-. ])?表示区号部分可选的分隔符
5.(\\d{3})表示号码的下三位数字
6.([-. ])?表示可选的分隔符
7.(\\d{4})表示号码的最后四位数字
完整的代码如下:
#include <iostream>
#include <string>
#include <regex>
using namespace std;
bool valid(const smatch& m)
{
//如果区号前有一个左括号
if (m[1].matched)
//则区号后必须有一个有括号,之后紧跟剩余号码或者一个空格
return m[3].matched && (m[4].matched == 0 || m[4].str() == " ");
else
//否则,区号后不能有右括号
//另两个组成部分间的分隔符必须匹配
return !m[3].matched&&m[4].str() == m[6].str();
}
int main()
{
//构造正则表达式
string phone("(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ])?(\\d{4})");
regex r(phone,regex::icase);
smatch m;
//输入
string s;
while (getline(cin, s))
{
//对每个匹配的电话号码
for (sregex_iterator it(s.begin(), s.end(), r), end_it; it != end_it; ++it)
//检查号码的格式是否合法
if (valid(*it))
cout << "valid: " << it->str() << endl;
else
cout << "not valid: " << it->str() << endl;
}
return 0;
}
3.3 使用
regex_replace
将美国的电话号码转换为"ddd.ddd.dddd"的形式
我们用一个
符号$后跟子表达式的索引号来表示一个特定的子表达式:
string fmt = "$2.$5.$7"; //将号码格式改为ddd.ddd.dddd
源代码如下:
#include <iostream>
#include <string>
#include <regex>
using namespace std;
int main()
{
//构造正则表达式
string phone("(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ])?(\\d{4})");
regex r(phone,regex::icase);
//输入
string s;
string fmt("$2.$5.$7");
while (getline(cin, s))
cout << regex_replace(s,r,fmt) << endl;
}
输入:
(908) 555-1800
输出:
908.555.1800
文章参考: