C++11--正则表达式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/i_chaoren/article/details/79230773

本文主要参考为《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中有两个名为 prefixsuffix的成员,分别返回表示输入序列中当前匹配之前和之后部分的 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

文章参考:

猜你喜欢

转载自blog.csdn.net/i_chaoren/article/details/79230773