正则和c++
一、简介
二、四种行为
1、匹配捕获
(1)匹配函数只有完全匹配整个字符串(或者从给定的位置开始的字符串),才会返回true;
(2)如果要保存匹配的结果,使用smatch result来保存;result[0]是保存整个匹配结果的,result[i]保存第i个捕获组的匹配结果(即第i个括号中的内容),可以使用result.size()可以查看一共有多少个匹配结果。
(3)例子
regex pattern("([a-zA-Z]{5})_(\\d{4})"); string s = "Rosie_1997"; smatch result; if (regex_match(s, result, pattern)) { cout << "匹配成功" << endl; for (int i = 0; i <= result.size(); ++i) { cout << result[i] << endl; } } else cout << "匹配失败" << endl; string ss = "19970211_rosie_1997"; if (regex_match(ss.cbegin() + 9, ss.cend(), result, pattern))//从第10个字符开始匹配 { cout << "匹配成功" << endl; for (int i = 0; i <= result.size(); ++i) { cout << result[i] << endl; } } else cout << "匹配失败" << endl;
2、搜索捕获
(1)搜索给定字符串是否存在于模式匹配的子串之中,与match不同的是search是找是否存在子串,即模式串pattern是否是s的一部分。
(2)和match一样,search也可以使用smatch result来记录结果,但不同的是result[0]记录的从左到右第一个匹配的子串
(3)假如有多个子串符合模式,若想知道result[0]中存储的是第几个子串,可以用result.position()函数,返回数从0开始。
(4)如果想遍历整个源串,匹配所有符合模式的子串,可以用string的迭代器,用result.second()更新迭代器位置。result[0].first返回的是查找结果子串在源串中的迭代器位置,second返回的是子串后面的位置,smatch.prefix表示匹配子串在源串的前缀,subfix表示后缀。
(5)例子
//有多个子串符合匹配模式 regex pattern("\\d+"); string s = "51x41+(5-13/2)x3"; smatch result; string::const_iterator iter = s.cbegin(); string::const_iterator iter_end = s.cend(); while (regex_search(iter, iter_end, result, pattern)) { cout << "查找成功:" << result[0]<< endl; iter = result[0].second; } //子串有多个捕获组 cout << endl; regex p2("([a-zA-Z]{3})_(\\d{4})"); string ss = "32sMq_19988abc_89912"; iter = ss.cbegin(); iter_end = ss.cend(); while (regex_search(iter, iter_end, result, p2)) { cout << "查找成功:" << result[0] << endl; for (int i = 1; i <= result.size(); ++i) { cout << result[i] << endl; } iter = result[0].second; }
3、替换
//正则替换 regex pattern("[a-zA-Z]{3}"); string s = "32sMQ_19988abc_199912" , ss; cout << s << endl; ss = regex_replace(s, pattern, "-ops-"); cout << ss << endl; ss = regex_replace(s, pattern, "-ops$-");//$在替换里面是特殊字符,但是单个出现的时候似乎是不需要转义就可以正常输出 cout << ss << endl; ss = regex_replace(s, pattern, "-ops$$$-");//这里再次验证了我的观点,第一个$是作为转义符出现的,所以这里的替换的结果只有两个$ cout << ss << endl; ss = regex_replace(s, pattern, "-ops$&-");//$&表示被替换的子串,相当于缩写,举例来说,对于sMQ而言,$&就是sMQ cout << ss << endl; ss = regex_replace(s, pattern, "-ops$`-");//$`表示被替换的子串左侧的内容,举例来说,对于sMQ而言就是32;对于abc而言就是32sMQ_19988 cout << ss << endl; ss = regex_replace(s, pattern, "-ops$'-");//$`表示被替换的子串右侧的内容,举例来说,对于sMQ而言就是_19988abc_199912;对于abc而言就是_199912 cout << ss << endl; cout << endl; regex p2("(([a-zA-Z]{3})_(\\d{4}))"); ss = regex_replace(s, p2, "$1");//$1是整个捕获结果,也就是sMQ_1998和abc_1999,本身替换本身,故就是源串没变 cout << ss << endl; ss = regex_replace(s, p2, "$2");//$2是第一个捕获组,也就是sMQ和abc cout << ss << endl; ss = regex_replace(s, p2, "$3");//$3是1998和1999 cout << ss << endl; ss = regex_replace(s, p2, "$3_$2");//调换了顺序,将匹配子串的sMQ_1998替换成了1998_sMQ,另外一个同理 cout << ss << endl;
4、切割
//正则切割 string mail("123@qq.com,456@gmail.com,789@163.com,abc@my.com"); regex reg(","); sregex_token_iterator pos(mail.begin(), mail.end(), reg, -1);//-1获取的是分割词前面的部分,0则是分割词 decltype(pos) end; for (; pos != end; ++pos) { cout << pos->str() << endl; }
三、实例训练
1.匹配IP
void IP_match(string s) { cout << "原内容为:\n" << s << endl; //位数对齐 s = regex_replace(s, regex("(\\d+)"), "00$1"); cout << "位数对齐后:\n" << s << endl; //去掉多的0 s = regex_replace(s, regex("0*(\\d{3})"), "$1");//$1指的是最外层大括号的内容,比如00192是符合要求的子串,而192就是整个捕获组的内容 cout << "去0后:\n" << s << endl; //取出ip regex reg("\\s"); sregex_token_iterator pos(s.begin(),s.end(),reg,-1); decltype(pos) end; set<string> ip_set; for (; pos != end; ++pos) { ip_set.insert(pos->str()); } cout << "最后结果:\n"; //输出排序后的结果 for (auto elem : ip_set) { cout << regex_replace(elem, regex("0*(\\d+)"), "$1") << endl; } }