一.用正则表达式判断邮箱格式是否正确
1 #include <regex> 2 3 #include <iostream> 4 5 #include <string> 6 7 8 bool is_email_valid(const std::string& email) 9 { 10 11 const std::regex pattern("(\w+)(\.|_)?(\w*)@(\w+)(\.(\w+))+"); 12 //const std::regex pattern("(\w+)(\.|_)?(\w*)@(\w+)(\.|-)?(\w*)(\.(\w+))+");验证最全面
13 return std::regex_match(email, pattern); 14 15 } 16 17 18 int main() 19 20 { 21 22 std::string email1 = "marius.bancila@domain.com"; 23 24 std::string email2 = "mariusbancila@domain.com"; 25 26 std::string email3 = "marius_b@domain.co.uk"; 27 28 std::string email4 = "marius@domain"; 29 30 31 32 std::cout << email1 << " : " << (is_email_valid(email1) ? 33 34 "valid" : "invalid") << std::endl; 35 36 std::cout << email2 << " : " << (is_email_valid(email2) ? 37 38 "valid" : "invalid") << std::endl; 39 40 std::cout << email3 << " : " << (is_email_valid(email3) ? 41 42 "valid" : "invalid") << std::endl; 43 44 std::cout << email4 << " : " << (is_email_valid(email4) ? 45 46 "valid" : "invalid") << std::endl; 47 48 return 0; 49 }
运行结果
这里对is_email_valid()函数中的正则表达式做一个简短的说明,如果对于正则表示不是很清楚的同学就能很容易理解了。
const std::regex pattern("(\w+)(\.|_)?(\w*)@(\w+)(\.(\w+))+");
首先注意‘()’表示将正则表达式分成子表达式,每个‘()’之间的内容表示一个子表达式;‘’是一个转义字符,‘\’表示扔掉第二个‘’的转义特
性,‘w+’表示匹配一个或多个单词,‘+’表示重复一次或者多次,因此第一个子表达式的意思就是匹配一个或者多个单词;接着看第二个子表达式,‘|’
表示选择,出现‘.’或者‘_’,后面的‘?’表示该子表示出现一次或者零次,因此第二个子表示表示‘.’或‘_’出现不出现都匹配。第三个子表达式表示
出现一个单词,‘*’表示任意个字符。后面的子表示根据已经介绍的内容,已经可以容易理解,就不再赘述。通过对正则表达式匹配模式串的分析,可以容易理解
运行结果。
下面一个例子通过正则表达式识别和打印IP地址的各个部分:
1 #include <regex> 2 3 #include <iostream> 4 5 #include <string> 6 7 8 9 void show_ip_parts(const std::string& ip) 10 11 { 12 13 // regular expression with 4 capture groups defined with 14 15 // parenthesis (...) 16 17 const std::regex pattern("(\d{1,3}):(\d{1,3}):(\d{1,3}):(\d{1,3})"); 18 19 // object that will contain the sequence of sub-matches 20 21 std:: match_results<std::string::const_iterator> result; 22 23 // match the IP address with the regular expression 24 25 bool valid = std:: regex_match(ip, result, pattern); 26 27 std::cout << ip << " : " << (valid ? "valid" : "invalid") 28 29 << std::endl; 30 31 // if the IP address matched the regex, then print the parts 32 33 if(valid) 34 35 { 36 37 std::cout << "b1: " << result[1] << std::endl; 38 39 std::cout << "b2: " << result[2] << std::endl; 40 41 std::cout << "b3: " << result[3] << std::endl; 42 43 std::cout << "b4: " << result[4] << std::endl; 44 45 } 46 47 } 48 49 50 51 int main() 52 { 53 54 show_ip_parts("1:22:33:444"); 55 56 show_ip_parts("1:22:33:4444"); 57 58 show_ip_parts("100:200"); 59 60 return 0; 61 62 }
运行结果:
是对正则表达式的模式串做一个说明:首先还是通过‘()’将这个串分成几个子表达式,其中d表示匹配一个数字,{,}表示数字的个数,例如{1,3}可以理解为匹配一个小于1000的数字(1-3位数都符合匹配要求)。
程序中还使用了match_results类,用来保存匹配的每一个子序列。调用regex_match(ip,result,pattern),表示将ip中与模式串pattern匹配的结果放在result中。
result最后可以通过下标来访问各个匹配的子表达式。
1 #include <regex> 2 3 #include <iostream> 4 5 #include <string> 6 7 8 9 int main() 10 11 { 12 13 14 15 const std::tr1::regex pattern("(\w+day)"); 16 17 18 19 // the source text 20 21 std::string weekend = "Saturday and Sunday"; 22 23 std::smatch result; 24 25 bool match = std::regex_search(weekend, result, pattern); 26 27 if(match) 28 29 { 30 31 32 33 for(size_t i = 1; i < result.size(); ++i) 34 35 { 36 37 std::cout << result[i] << std::endl; 38 39 } 40 41 } 42 43 std::cout<<std::endl; 44 45 return 0; 46 47 }
运行结果:
上面这个例子只能返回第一个匹配的项,如果要返回所有匹配的子序列,可以使用下面的方式:
1 #include <regex> 2 3 #include <iostream> 4 5 #include <string> 6 7 8 9 int main() 10 11 { 12 13 // regular expression 14 15 const std::regex pattern("\w+day"); 16 17 18 19 // the source text 20 21 std::string weekend = "Saturday and Sunday, but some Fridays also."; 22 23 24 25 const std::sregex_token_iterator end; //需要注意一下这里 26 27 for (std::sregex_token_iterator i(weekend.begin(),weekend.end(), pattern); i != end ; ++i) 28 29 { 30 31 std::cout << *i << std::endl; 32 33 } 34 35 std::cout<<std::endl; 36 37 return 0; 38 39 }
运行结果:
下面的例子将元音字母打头的单词前面的a替换为an:
1 #include <regex> 2 3 #include <iostream> 4 5 #include <string> 6 7 8 9 int main() 10 11 { 12 13 // text to transform 14 15 std::string text = "This is a element and this a unique ID."; 16 17 18 19 // regular expression with two capture groups 20 21 const std::regex pattern("(\ba (a|e|i|u|o))+"); 22 23 24 25 // the pattern for the transformation, using the second 26 27 // capture group 28 29 std::string replace = "an $2"; 30 31 32 33 std::string newtext = std::regex_replace(text, pattern, replace); 34 35 36 37 std::cout << newtext << std::endl; 38 39 std::cout << std::endl; 40 41 return 0; 42 43 }
运行结果:
还是来说明一下,这里主要使用了regex_replace(text, pattern, replace),意思是将text的内容按照pattern进行匹配,匹配成功的使用replace串进行替换,并将替换后的结果作为函数值返回。需要 注意的是std::string replace = "an $2"; 这里‘$2’表示模式串的第二个子表达式,
也就是以a,e,i,o,u开头的单词。
三.下面一个例子将进行年月日格式的转换,将DD-MM-YYYY –> YYYY-MM-DD,其中‘.’或者‘/’都能正确识别。
1 #include <regex> 2 3 #include <iostream> 4 5 #include <string> 6 7 8 9 std::string format_date(const std::string& date) 10 11 { 12 13 // regular expression 14 15 const std:: regex pattern("(\d{1,2})(\.|-|/)(\d{1,2})(\.|-|/)(\d{4})"); 16 17 18 19 // transformation pattern, reverses the position of all capture groups 20 21 std::string replacer = "$5$4$3$2$1"; 22 23 24 25 // apply the tranformation 26 27 return std:: regex_replace(date, pattern, replacer); 28 29 } 30 31 32 33 int main() 34 35 { 36 37 std::string date1 = "1/2/2008"; 38 39 std::string date2 = "12.08.2008"; 40 41 42 43 std::cout << date1 << " -> " << format_date(date1) << std::endl; 44 45 std::cout << date2 << " -> " << format_date(date2) << std::endl; 46 47 std::cout << std::endl; 48 49 return 0; 50 51 }
运行结果:
说明,这个例子也很有实用价值,这里用到的正则表达式的匹配模式前面都已经进行过说明就不在分析。
相信通过以上例子,对正则表达式的运用已经有了一个不错的了解,下面再来添加一个实例,加深一下理解。
下面一个例子用来查找给定文本中new的个数和delete的个数是否相等:
1 #include <iostream> 2 3 #include <string> 4 5 #include <regex> 6 7 8 9 10 11 int main() { 12 13 // "new" and "delete" 出现的次数是否一样? 14 15 std::regex reg("(new)|(delete)"); 16 17 std::smatch m; 18 19 std::string s= 20 21 "Calls to new must be followed by delete. 22 23 Calling simply new results in a leak!"; 24 25 int new_counter=0; 26 27 int delete_counter=0; 28 29 std::string::const_iterator it=s.begin(); 30 31 std::string::const_iterator end=s.end(); 32 33 34 35 while (std::regex_search(it,end,m,reg)) 36 37 { 38 39 // 是 new 还是 delete? 40 41 m[1].matched ? ++new_counter : ++delete_counter; 42 43 it=m[0].second; 44 45 } 46 47 48 49 if (new_counter!=delete_counter) 50 51 std::cout << "Leak detected! "; 52 53 else 54 55 std::cout << "Seems ok... "; 56 57 std::cout << std::endl; 58 59 }
运行结果:
运行结果表明,new和delete的数量不相等,也就是发生了“内存泄露”。
为了帮助理解,上面对于match_results类型的下标操作的意义,请看ISOIEC14882 C++11的说明:
1 #include <iostream> 2 3 #include <string> 4 5 #include <regex> 6 7 using namespace std; 8 9 10 11 class regex_callback { 12 13 int sum_; 14 15 public: 16 17 regex_callback() : sum_(0) {} 18 19 20 21 template <typename T> void operator()(const T& what) { 22 23 sum_+=atoi(what[1].str().c_str()); 24 25 } 26 27 28 29 int sum() const { 30 31 return sum_; 32 33 } 34 35 }; 36 37 38 39 int main() { 40 41 regex reg("(\d+),?"); 42 43 string s="1,1,2,3,5,8,13,21"; 44 45 46 47 sregex_iterator it(s.begin(),s.end(),reg); 48 49 sregex_iterator end; 50 51 52 53 regex_callback c; 54 55 int sum=for_each(it,end,c).sum();//for_each返回的是这个函数对象,因此可以调用sum 56 57 58 59 cout<<sum<<endl; 60 61 cout<<endl; 62 63 }
运行结果:
1 #include <iostream> 2 3 #include <string> 4 5 #include <regex> 6 7 using namespace std; 8 9 int main() 10 11 { 12 13 regex reg("/"); 14 15 vector<std::string> vec; 16 17 string s="Split/Vulue/Teather/Neusoft/Write/By/Lanwei"; 18 19 sregex_token_iterator it(s.begin(),s.end(),reg,-1);//// -1逆向匹配,就是匹配除了'/'之外的 20 21 sregex_token_iterator end ; 22 23 while(it!=end) 24 25 vec.push_back(*it++); 26 27 copy(vec.begin(),vec.end(),ostream_iterator<std::string>( cout," ")); 28 29 }
运行结果: