C++ 正则表达式示例

一、正则表达式类对象

  C++标准库中提供了对正则表达式的支持,一下是常用的使用方法:

  1. regex 类:

    定义包含正则表达式的对象,如regex rx("a(b?)c");

  2. cmath 类:

    定义保存匹配结果的对象;

    当待搜索的字符串是char类型时,使用此类对象;

  3. smath 类:

    定义保存匹配结果的对象;

    当待搜索的字符串是string类型时,使用此类对象;

  4. 常用正则匹配函数:

    4.1 bool regex_match(...)

    判断是否准确匹配整个目标字符串,是目标字符串和正则表达式要完全匹配时才返回TRUE;

    如"abc"和"ab*c" 完全匹配,但是如果是"abcd"和"ab*c",虽然只有部分匹配(abc)但是返回是false;

    4.2 bool regex_search(...)

    在目标字符串中搜索一个匹配正则的字符串,如果搜索到了则返回true,否则返回false;

    4.3 regex_replace(...)

    用指定的字符串替换匹配到的字符串,默认是替换所有目标字符串中匹配到的字符串,加了format_first_only标志表示只替换第一次匹配到的字符串;

二、使用示例

  

 1 #include <iostream>
 2 #include <sstream>
 3 #include <fstream>
 4 #include <string>
 5 #include <regex>
 6 
 7 using namespace std;
 8 
 9 int main(int argc, char * argv[])
10 {
11     const char * first = "abc"; //待匹配字符串
12     const char * last = first + strlen(first);
13     cmatch narrowMatch; //char *类型的对象来匹配保存结果
14     regex rx("ab*c"); //定义包含正则表达式的对象
15 
16     // 注意:regex_match是目标字符串和正则表达式要完全匹配时才返回true.  
17     // 如"abc"和"ab*c"完全匹配返回true,但是如果是"abcd"和"ab*c",虽然只有  
18     // 部分匹配(abc)但是返回是false  
19     // regex_match有多个重载函数,可以只有三个参数,不保存结果.  
20     // 也可以有四个参数,第三个参数用来保存结果,一般情况下使用三个参数的就可以了  
21     bool found = regex_match(
22                                 first, //待匹配开始位置
23                                 last, //待匹配的结束位置
24                                 narrowMatch, // 保存结果
25                                 rx //正则表达式
26                                 );
27 
28     cout << found << endl;
29     //cout << narrowMatch << endl; //错误
30 
31     string target2("Drizzle");
32     regex rx2("(D\\w+e)");
33     smatch result;
34     found = regex_match(
35                             target2.cbegin(), //匹配开始 -->迭代器区间开始开始位置
36                             target2.cend(), //匹配结束 -->迭代器区间结束位置 
37                             result, //保存结果
38                             rx2 //正则表达式
39                             );
40     cout << found << endl;
41     //cout << result << endl; //错误
42 }
 1 #include <iostream>
 2 #include <regex>
 3 #include <fstream>
 4 #include <string>
 5 #include <sstream>
 6 
 7 using namespace std;
 8 
 9 int main(void)
10 {
11     const char * first = "abcd";
12     const char * last = first + strlen(first);
13     cmatch mr; //保存匹配结果, 可打印
14     regex rx("abc"); 
15     std::regex_constants::match_flag_type fl = std::regex_constants::match_default; //匹配标志 
16 
17     // 给定目标字符串的起始和结束位置
18     // 完全和正则表达式匹配,不同于regex_match()
19     // 可打印正确匹配的结果,不同于regex_match()
20     bool search1 = regex_search(first, first+1, rx, fl);
21     cout << "search1: " << search1 << endl;
22 
23     bool search2 = regex_search(first, last, mr, rx);
24     cout << "search2: " << search2 << "; mr: " << mr.str() << endl;
25 
26     // 给定待匹配的字符串(char类或string类)
27     bool search3 = regex_search("a", //待匹配字符串 
28                                 rx);
29     cout << "search3: " << search3 << endl;
30 
31     bool search4 = regex_search("xabcd", mr, rx);
32     cout << "search4: " << search4 << "; mr: " << mr.str() << endl;
33 
34     bool search5 = regex_search(string("a"), //待匹配对象,string类 
35                                         rx);
36     cout << "search5: " << search5 << endl;
37 
38     string st("abcabc");
39     smatch mr2; //保存匹配结果,可打印
40     bool search6 = regex_search(st, mr2, rx);
41     cout << "search6: " << search6 << "; mr2: " << mr2.str() << endl;
42 
43     return 0;
44 }
 1 #include <iostream>
 2 #include <sstream>
 3 #include <string>
 4 #include <regex>
 5 
 6 using namespace std;
 7 
 8 int main(void)
 9 {
10     char buf[20];
11     const char * first = "axayaz";
12     const char * last = first + strlen(first);
13 
14     regex rx("a");
15     string fmt("A");
16     regex_constants::match_flag_type fonly = regex_constants::format_first_only;
17 
18     // 默认是替换所有目标字符串总匹配到的字符串
19     // format_first_only标志表示只替换第一次匹配到的字符串
20     // 输出替换后的字符串
21     *regex_replace(
22                     &buf[0], //被更改字符串的迭代器 
23                     first, 
24                     last,
25                     rx,
26                     fmt //要替换的字符串  
27                     ) = '\0';
28     cout << "replacement1: " << &buf[0] << endl;
29 
30     *regex_replace(
31                     &buf[0],
32                     first,
33                     last,
34                     rx,
35                     fmt,
36                     fonly //替换标志,在此表示只替换第一次匹配到的字符串  
37                     ) = '\0';
38     cout << "replacement2: " << &buf[0] << endl;
39 
40     string str("adaeaf");
41     string replacement3 = regex_replace(
42                                         str,
43                                         rx,
44                                         fmt
45                                         );
46     cout << "replacement3: " << replacement3 << endl;
47 
48     string replacement4 = regex_replace(
49                                         str,
50                                         rx,
51                                         fmt,
52                                         fonly
53                                         );
54     cout << "replacement4: " << replacement4 << endl;
55 
56     return 0;
57 }
 1 #include <iostream>
 2 #include <regex>
 3 #include <fstream>
 4 #include <string>
 5 #include <sstream>
 6 
 7 using namespace std;
 8 
 9 int main(void)
10 {
11     const char * first = "abcd";
12     const char * last = first + strlen(first);
13     cmatch mr; //保存匹配结果, 可打印
14     regex rx("abc"); 
15     std::regex_constants::match_flag_type fl = std::regex_constants::match_default; //匹配标志 
16 
17     // 给定目标字符串的起始和结束位置
18     // 完全和正则表达式匹配,不与待搜索字符串同长度,不同于regex_match()
19     // 可打印正确匹配的结果,不同于regex_match()
20     bool search1 = regex_search(first, first+1, rx, fl);
21     cout << "search1: " << search1 << endl;
22 
23     bool search2 = regex_search(first, last, mr, rx);
24     cout << "search2: " << search2 << "; mr: " << mr.str() << endl;
25 
26     // 给定待匹配的字符串(char类或string类)
27     bool search3 = regex_search("a", //待匹配字符串 
28                                 rx);
29     cout << "search3: " << search3 << endl;
30 
31     bool search4 = regex_search("xabcd", mr, rx);
32     cout << "search4: " << search4 << "; mr: " << mr.str() << endl;
33 
34     bool search5 = regex_search(string("a"), //待匹配对象,string类 
35                                         rx);
36     cout << "search5: " << search5 << endl;
37 
38     string st("abcabc");
39     smatch mr2; //保存匹配结果,可打印
40     bool search6 = regex_search(st, mr2, rx);
41     cout << "search6: " << search6 << "; mr2: " << mr2.str() << endl;
42 
43     ///////////////////////////////4.regex_search(...)循环遍历字符串示例/////////////////////////  
44     ///       --------->找到目标字符串中所有匹配的子串  
45     ///       ####----->此示例中找到s串中所有以subj开头的单词,并打印出来  
46     ///////////////////////////////////////////////////////////////////////////////////////////
47     string s("this subject has a subjmarine as a subjsequence subjmite");
48     smatch m;
49     regex e("\\b(subj)([^ ]*)/"); 
50     while (regex_search(s, m, e))
51     {
52         cout << m.str() << endl;
53         s = m.suffix().str();
54     }
55 
56     return 0;
57 }

 三、特殊字符及语法表达式

参考:
http://deerchao.net/tutorials/regex/regex.htm
http://www.regexlab.com/zh/regref.htm
http://www.cplusplus.com/reference/regex/ECMAScript/

正则表达式(regular expression)就是用一个“字符串”来描述一个特征,然后去验证另一个“字符串”是否符合这个特征。比如 表达式“ab+” 描述的特征是“一个 ‘a’ 和 任意个 ‘b’ ”,那么 ‘ab’, ‘abb’, ‘abbbbbbbbbb’ 都符合这个特征。

正则表达式可以用来:

  1. 验证字符串是否符合指定特征,比如验证是否是合法的邮件地址。
  2. 用来查找字符串,从一个长的文本中查找符合指定特征的字符串,比查找固定字符串更加灵活方便。
  3. 用来替换,比普通的替换更强大。

从c++ 11开始,标准c++库在 里面提供了正则表达式的支持。默认的,c++ regex正则表达式使用的是ECMAScript语法。

ECMAScript语法

普通字符

字母、数字、汉字、下划线、以及后边没有提到的特殊模式字符,都是”普通字符”。表达式中的普通字符,在匹配一个字符串的时候,匹配与之相同的一个字符。

举例1:表达式 “c”,在匹配字符串 “abcde” 时,匹配结果是:成功;匹配到的内容是:”c”;匹配到的位置是:开始于2,结束于3。(注:下标从0开始还是从1开始,因当前编程语言的不同而可能不同)

举例2:表达式 “bcd”,在匹配字符串 “abcde” 时,匹配结果是:成功;匹配到的内容是:”bcd”;匹配到的位置是:开始于1,结束于4。

特殊模式字符

特殊模式字符是在正则表达式中有特殊含义的字符,比如代表某些无法用字符串表达的字符或者代表一类字符。

表达式 可匹配
r 回车
n 换行
f 换页
t 水平制表符
v 数值制表符
. 除了行结束符(LF CR LS PS)外所有字符(LF换行,CR回车,LS行分割,PS段落分割)
d 0~9 中的任意一个数字
D d的反面
w 任意一个字母或数字或下划线,也就是 A~Z,a~z,0~9,_ 中任意一个
W w的反面
s 包括空格、制表符、换页符等空白字符的其中任意一个
S s的反面

字符类

使用方括号 [ ] 包含一系列字符,能够匹配其中任意一个字符。用 [^ ] 包含一系列字符,则能够匹配其中字符之外的任意一个字符。同样的道理,虽然可以匹配其中任意一个,但是只能是一个,不是多个。

表达式 可匹配
[ab5@] 匹配 “a” 或 “b” 或 “5” 或 “@”
[^abc] 匹配 “a”,”b”,”c” 之外的任意一个字符
[f-k] 匹配 “f”~”k” 之间的任意一个字母
[^A-F0-3] 匹配 “A”~”F”,”0″~”3″ 之外的任意一个字符

举例1:表达式 “[bcd][bcd]” 匹配 “abc123” 时,匹配的结果是:成功;匹配到的内容是:”bc”;匹配到的位置是:开始于1,结束于3。

举例2:表达式 “[^abc]” 匹配 “abc123” 时,匹配的结果是:成功;匹配到的内容是:”1″;匹配到的位置是:开始于3,结束于4。

量词

字符 次数
* 0到无限次
+ 1到无限次
? 0到1次
{int} int次
{int,} int到无限次
{min,max} 大于等于min次,小于等于max次

举例1:表达式 “d+.?d*” 在匹配 “It costs $12.5” 时,匹配的结果是:成功;匹配到的内容是:”12.5″;匹配到的位置是:开始于10,结束于14。

举例2:表达式 “go{2,8}gle” 在匹配 “Ads by goooooogle” 时,匹配的结果是:成功;匹配到的内容是:”goooooogle”;匹配到的位置是:开始于7,结束于17。

默认的,这些量词都是贪婪的,就是他们会尽可能的去匹配最多的字符。在量词后面加上?,这些行为可以改成懒惰的。
比如:”(a+).*”去匹配”aardvark”,得到结果是”aa”。
“(a+?).*”去匹配”aardvark”,得到结果是”a”。

贪婪与懒惰

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。以这个表达式为例:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。

有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:

a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。

懒惰限定符

表达式 匹配
*? 重复任意次,但尽可能的少
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

分组

分组可以使量词作用在几个字符上。有两种分组:

字符 描述 效果
(subpattern) Group 创造反向引用
(?:subpattern) Passive Group 不创造反向引用

当分组创建了一个反向引用,分组内的子表达式会存储成一个子匹配。每个子匹配的都是以左括号出现次序为数字的索引。第一个子匹配是1,第二个是2,一次类推。这些子匹配可以用在后续的正则表达式中。

选择

模式中存在不同的可选部分。

举例5:表达式 “Tom|Jack” 在匹配字符串 “I’m Tom, he is Jack” 时,匹配结果是:成功;匹配到的内容是:”Tom”;匹配到的位置是:开始于4,结束于7。匹配下一个时,匹配结果是:成功;匹配到的内容是:”Jack”;匹配到的位置时:开始于15,结束于19。

举例6:表达式 “(gos*)+” 在匹配 “Let’s go go go!” 时,匹配结果是:成功;匹配到内容是:”go go go”;匹配到的位置是:开始于6,结束于14。

举例7:表达式 “¥(d+.?d*)” 在匹配 “$10.9,¥20.5” 时,匹配的结果是:成功;匹配到的内容是:”¥20.5″;匹配到的位置是:开始于6,结束于10。单独获取括号范围匹配到的内容是:”20.5″。

反向引用

表达式在匹配时,表达式引擎会将小括号 “( )” 包含的表达式所匹配到的字符串记录下来。在获取匹配结果的时候,小括号包含的表达式所匹配到的字符串可以单独获取。在实际应用场合中,当用某种边界来查找,而所要获取的内容又不包含边界时,必须使用小括号来指定所要的范围。

其实,”小括号包含的表达式所匹配到的字符串” 不仅是在匹配结束后才可以使用,在匹配过程中也可以使用。表达式后边的部分,可以引用前面 “括号内的子匹配已经匹配到的字符串”。引用方法是 “” 加上一个数字。”1″ 引用第1对括号内匹配到的字符串,”2″ 引用第2对括号内匹配到的字符串……以此类推,如果一对括号内包含另一对括号,则外层的括号先排序号。换句话说,哪一对的左括号 “(” 在前,那这一对就先排序号。

举例1:表达式 “(‘|”)(.*?)(1)” 在匹配 ” ‘Hello’, “World” ” 时,匹配结果是:成功;匹配到的内容是:” ‘Hello’ “。再次匹配下一个时,可以匹配到 ” “World” “。

举例2:表达式 “(w)1{4,}” 在匹配 “aa bbbb abcdefg ccccc 111121111 999999999” 时,匹配结果是:成功;匹配到的内容是 “ccccc”。再次匹配下一个时,将得到 999999999。这个表达式要求 “w” 范围的字符至少重复5次,点击测试 注意与 “w{5,}” 之间的区别。

举例3:表达式 “<(w+)s*(w+(=(‘|”).*?4)?s*)*>.*?</1>” 在匹配 ”

” 时,匹配结果是成功。如果 ” ” 与 ”

” 不配对,则会匹配失败;如果改成其他配对,也可以匹配成功。

断言

断言是判断字符出现位置的条件,它本身不代表任何字符。

字符 描述 匹配条件
^ 行开始 一行的开头或者紧跟行结束符后面
$ 行结束 一行的末尾或者紧跟行结束前面
b 字符边界 开头和结尾被认为是非字符
B 非字符边界 开头和结尾被认为是非字符
(?=subpattern) 正向预搜索匹配 正向预搜索匹配
(?!subpattern) 正向预搜索不匹配 正向预搜索不匹配

格式:”(?=xxxxx)”,在被匹配的字符串中,它对所处的 “缝隙” 或者 “两头” 附加的条件是:所在缝隙的右侧,必须能够匹配上 xxxxx 这部分的表达式。因为它只是在此作为这个缝隙上附加的条件,所以它并不影响后边的表达式去真正匹配这个缝隙之后的字符。这就类似 “b”,本身不匹配任何字符。”b” 只是将所在缝隙之前、之后的字符取来进行了一下判断,不会影响后边的表达式来真正的匹配。

举例1:表达式 “Windows (?=NT|XP)” 在匹配 “Windows 98, Windows NT, Windows 2000” 时,将只匹配 “Windows NT” 中的 “Windows “,其他的 “Windows ” 字样则不被匹配。

格式:”(?!xxxxx)”,所在缝隙的右侧,必须不能匹配 xxxxx 这部分表达式。

举例3:表达式 “((?!bstopb).)+” 在匹配 “fdjka ljfdl stop fjdsla fdj” 时,将从头一直匹配到 “stop” 之前的位置,如果字符串中没有 “stop”,则匹配整个字符串。

举例4:表达式 “do(?!w)” 在匹配字符串 “done, do, dog” 时,只能匹配 “do”。在本条举例中,”do” 后边使用 “(?!w)” 和使用 “b” 效果是一样的。

posted on 2017-11-24 20:11  萧飞IDO  阅读(5813)  评论(0编辑  收藏  举报

导航