1. 介绍

正则表达式(Regular Expression,常简写为regex、regexp或RE)。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。C++11开始支持正则表达式。
正则表达式非常强大,具体的实现算法有差异,所以会有多种实现方式。C++11支持6种正则表达式引擎。ECMAScript 是其中支持最多元素的引擎,也是regex默认支持的引擎。

  • ECMAScript
  • basic(POSIX Basic Regular Expressions)
  • extended(POSIX Extended Regular Expressions )
  • awk(POSIX awk)
  • grep(POSIX grep )
  • egrep(POSIX grep –E)

2. 正则表达式语法

正则表达式主要两部分构成,特殊字符和普通字符。

  1. “.”: 匹配除"\n"之外的任何单个字符,若要匹配包括"\n"在内的任意字符,需使用诸如"[\s\S]"之类的模式;

  2. “^”:匹配输入字符串的开始位置,不匹配任何字符,要匹配”^”字符本身,需使用”^”;

  3. “$”:匹配输入字符串结尾的位置,不匹配任何字符,要匹配”$”字符本身,需使用”$”;

  4. “*”: 零次或多次匹配前面的字符或子表达式,”*”等效于”{0,}”,如”^*b”可以匹配”b”、”^b”、”^^b”、…;

  5. “+”: 一次或多次匹配前面的字符或子表达式,等效于”{1,}”,如”a+b”可以匹配”ab”、”aab”、”aaab”、…;

  6. “?”: 零次或一次匹配前面的字符或子表达式,等效于”{0,1}”,如”a[cd]?”可以匹配”a”、”ac”、”ad”; 当此字符紧随任何其他限定符”*”、”+”、”?”、”{n}”、”{n,}”、”{n,m}”之后时,匹配模式是"非贪心的"。"非贪心的"模式匹配搜索到的、尽可能短的字符串,而默认的"贪心的"模式匹配搜索到的、尽可能长的字符串。如,在字符串"oooo"中,"o+?“只匹配单个"o”,而"o+“匹配所有"o”;

  7. “|”:将两个匹配条件进行逻辑"或"(Or)运算,如正则表达式”(him|her)”匹配"itbelongs to him"和"it belongs to her",但是不能匹配"itbelongs to them.";

  8. “\”: 将下一字符标记为特殊字符、文本、反向引用或八进制转义符,如,”n”匹配字符”n”,”\n”匹配换行符,序列”\”匹配”\”,”(“匹配”(“;

  9. “\w”:匹配字母或数字或下划线,任意一个字母或数字或下划线,即A~Z,a~z,0~9,_中任意一个;

  10. “\W”:匹配任意不是字母、数字、下划线的字符;

  11. “\s”:匹配任意的空白符,包括空格、制表符、换页符等空白字符的其中任意一个,与”[ \f\n\r\t\v]”等效;

  12. “\S”:匹配任意不是空白符的字符,与”[^\f\n\r\t\v]”等效;

  13. “\d”:匹配数字,任意一个数字,0~9中的任意一个,等效于”[0-9]”;

  14. “\D”:匹配任意非数字的字符,等效于”[^0-9]”;

  15. “\b”: 匹配一个字边界,即字与空格间的位置,也就是单词和空格之间的位置,不匹配任何字符,如,“er\b"匹配"never"中的"er”,但不匹配"verb"中的"er";

  16. “\B”: 非字边界匹配,“er\B"匹配"verb"中的"er”,但不匹配"never"中的"er";

  17. “\f”:匹配一个换页符,等价于”\x0c”和”\cL”;

  18. “\n”:匹配一个换行符,等价于”\x0a”和”\cJ”;

  19. “\r”:匹配一个回车符,等价于”\x0d”和”\cM”;

  20. “\t”:匹配一个制表符,等价于”\x09”和”\cI”;

  21. “\v”:匹配一个垂直制表符,等价于”\x0b”和”\cK”;

  22. “\cx”:匹配”x”指示的控制字符,如,\cM匹配Control-M或回车符,”x”的值必须在”A-Z”或”a-z”之间,如果不是这样,则假定c就是"c"字符本身;

  23. “{n}”:”n”是非负整数,正好匹配n次,如,"o{2}"与"Bob"中的"o"不匹配,但与"food"中的两个"o"匹配;

  24. “{n,}”:”n”是非负整数,至少匹配n次,如,"o{2,}“不匹配"Bob"中的"o”,而匹配"foooood"中的所有”o”,"o{1,}“等效于"o+”,"o{0,}“等效于"o*”;

  25. “{n,m}”:”n”和”m”是非负整数,其中n<=m,匹配至少n次,至多m次,如,"o{1,3}"匹配"fooooood"中的头三个o,'o{0,1}‘等效于’o?’,注意,不能将空格插入逗号和数字之间;如”ba{1,3}”可以匹配”ba”或”baa”或”baaa”;

  26. “x|y”:匹配”x”或”y”,如,”z|food”匹配"z"或"food";”(z|f)ood”匹配"zood"或"food";

  27. “[xyz]”:字符集,匹配包含的任一字符,如,"[abc]“匹配"plain"中的"a”;

  28. “[^xyz]””:反向字符集,匹配未包含的任何字符,匹配除了”xyz”以外的任意字符,如,"[^abc]“匹配"plain"中的"p”;

  29. “[a-z]”:字符范围,匹配指定范围内的任何字符,如,"[a-z]"匹配"a"到"z"范围内的任何小写字母;

  30. “[^a-z]”:反向范围字符,匹配不在指定的范围内的任何字符,如,"[^a-z]"匹配任何不在"a"到"z"范围内的任何字符;

  31. “( )”:将”(“和”)”之间的表达式定义为”组”group,并且将匹配这个表达式的字符保存到一个临时区域,一个正则表达式中最多可以保存9个,它们可以用”\1”到”\9”的符号来引用;

  32. “(pattern)”:匹配pattern并捕获该匹配的子表达式,可以使用$0…$9属性从结果”匹配”集合中检索捕获的匹配;"$0"表示整个匹配,"$1"表示第1个子表达式的匹配结果。当只有一个子表达式时两者可能是相同。

  33. “(?:pattern)”:匹配pattern但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配,这对于用”or”字符” (|)”组合模式部件的情况很有用, 如,”industr(?:y|ies)”是比”industry|industries”更简略的表达式;

  34. “(?=pattern)”: 非获取匹配,正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。如,“Windows(?=95|98|NT|2000)“能匹配"Windows2000"中的"Windows”,但不能匹配"Windows3.1"中的"Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始;

  35. “(?!pattern)”: 非获取匹配,正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。如"Windows(?!95|98|NT|2000)“能匹配"Windows3.1"中的"Windows”,但不能匹配"Windows2000"中的"Windows";

3. 正则表达式的使用

  • 目标序列(Target sequence)。为模式而搜索到的字符序列。这可以是二个迭代器所指定的范围、空终止字符串或一个 std::string 。
  • 模式(Pattern)。这是正则表达式自身。它确定构成匹配者。它是从带特定语法的字符串构成的 std::basic_regex 类型对象。受支持的语法变体的描述见 syntax_option_type 。
  • 匹配的数组(Matched array)。关于匹配的信息可作为 std::match_results 类型对象获取。
  • 替换字符串(Replacement string)。这是确定如何替换匹配的字符串,受支持的语法变体的描述不同而不同。

3.1 基本类

为了支持宽字符和窄字符,所以正则表达式的类基本上是通过类模块来实现的。

typedef basic_regex<char> regex;                     // 正则表达式对象
typedef basic_regex<wchar_t> wregex;
typedef match_results<const char *> cmatch;             // 标识一个正则表达式匹配,包含所有子表达式匹配(字符指针)
typedef match_results<const wchar_t *> wcmatch;
typedef match_results<string::const_iterator> smatch; // 标识一个正则表达式匹配,包含所有子表达式匹配(字符串)
typedef match_results<wstring::const_iterator> wsmatch;
typedef sub_match<const char *> csub_match;             // 标识子表达式所匹配的字符序列
typedef sub_match<const wchar_t *> wcsub_match;

3.2. 算法

算法将封装于 regex 的正则表达式应用到字符的目标序列,算法主要是由函数模块来实现的。

  • regex_match,试图匹配正则表达式到整个字符序列 。
  • regex_search,试图匹配正则表达式到字符序列的任何部分 。
  • regex_replace,以格式化的替换文本来替换正则表达式匹配的出现位置 。

3.3. 迭代器

迭代器用于遍历在序列中找到的匹配正则表达式的整个集合。

  • regex_iterator,在字符序列中通过所有正则表达式匹配迭代 。
  • regex_token_iterator,通过在给定的字符串中所有正则表达式匹配中的指定子表达式,或通过不匹配的子串迭代 。

3.4 异常

regex_error定义一个对象抛出来自正则表达式库 的异常。

4. 示例

以下代码使用VS2010进行编译测试。

4.1. regex_match

#include "stdafx.h"
#include <regex>  // Must be included
#include <string>
#include <iostream>
using namespace std;int _tmain(int argc, _TCHAR* argv[])
{// .通配符,几个代表几个字符std::string strSrc = "Simple";std::regex rePattern1("Simpl.");cout<<boolalpha<<std::regex_match(strSrc, rePattern1)<<endl;  // truestd::regex rePattern2("Simp..");cout<<boolalpha<<std::regex_match(strSrc, rePattern2)<<endl;  // true// ^在regex_match中的作用无法体现,因为regex_match就要求必须从开始匹配std::regex rePattern3(".impl.");cout<<boolalpha<<std::regex_match(strSrc, rePattern3)<<endl; // truestd::regex rePattern4("^.impl.");cout<<boolalpha<<std::regex_match(strSrc, rePattern4)<<endl; // true// regex_match可以用作单纯的匹配判断,也可以匹配获得具体的结果// 匹配的结果存放在smatch中.smatch中0索引存放完整匹配的结果,1存放第1个()匹配的结果// 从smatch中取元素,既可以用[],也可以用str(idx)std::smatch matchRes1;strSrc = "foot.txt";std::regex rePattern5("(foot)\\.txt"); // \\.使用转义字符cout<<boolalpha<<std::regex_match(strSrc, matchRes1, rePattern5)<<endl; // truecout<<matchRes1[0]<<":"<<matchRes1[1]<<endl; // foot.txt:footstd::regex rePattern6("(....)\\.txt"); // \\.使用转义字符cout<<boolalpha<<std::regex_match(strSrc, matchRes1, rePattern6)<<endl; // truecout<<matchRes1[0]<<":"<<matchRes1[1]<<endl; // foot.txt:footcout<<matchRes1[0]<<":"<<matchRes1.str(1)<<endl; // foot.txt:footstd::ssub_match ssMatch = matchRes1[1];// ssMatch支持强制转换成string类型,和ssMatch.str()等价cout<<matchRes1[0]<<":"<<ssMatch<<endl; // foot.txt:footcout<<matchRes1[0]<<":"<<ssMatch.str()<<endl; // foot.txt:foot// *表示匹配前面的o,0或多个均可。即strSrc为ft.txt,fot.txt,foot.txt均匹配成功std::regex rePattern7("fo*t\\.txt"); // \\.使用转义字符cout<<boolalpha<<std::regex_match(strSrc, matchRes1, rePattern7)<<endl; // true// +表示匹配前面的o,1或多个均可。即strSrc为fot.txt,foot.txt均匹配成功,ft.txt匹配不成功std::regex rePattern8("fo+t\\.txt"); // \\.使用转义字符cout<<boolalpha<<std::regex_match(strSrc, matchRes1, rePattern8)<<endl; // true// ?表示匹配前面的o,0或1个均可。即strSrc为ft.txt,fot.txt均匹配成功,foot.txt匹配不成功std::regex rePattern9("fo?t\\.(txt)"); // \\.使用转义字符cout<<boolalpha<<std::regex_match(strSrc, matchRes1, rePattern9)<<endl; // false// 下面有两个括号,即对应两个匹配元素[1],[2]std::regex rePattern10("(foo?t)\\.(txt)"); // \\.使用转义字符cout<<boolalpha<<std::regex_match(strSrc, matchRes1, rePattern10)<<endl; // truecout<<matchRes1[0]<<":"<<matchRes1.str(1)<<":"<<matchRes1[2]<<endl; // foot.txt:foot:txt// (ab)是子表达式,(ab)+表示匹配1个或多个ab.strSrc = "abab.txt";std::regex rePattern11("(ab)+\\.(txt)"); // 可匹配ab.txt,abab.txt,ababab.txt等cout<<boolalpha<<std::regex_match(strSrc, matchRes1, rePattern11)<<endl; // truecout<<matchRes1[0]<<":"<<matchRes1.str(1)<<":"<<matchRes1[2]<<endl;      // abab.txt:ab:txt// (ab|cd)是子表达式,(ab|cd)+表示匹配1个或多个ab或cd.strSrc = "abcdab.txt";std::regex rePattern12("(ab|cd)+\\.(txt)"); // 可匹配ab.txt,cd.txt,abcde.txt等cout<<boolalpha<<std::regex_match(strSrc, matchRes1, rePattern12)<<endl; // truecout<<matchRes1[0]<<":"<<matchRes1.str(1)<<":"<<matchRes1.str(2)<<endl;  // abcdab.txt:ab:txt// {n}表示匹配前面的字符或子表达式n次strSrc = "abab.txt";std::regex rePattern13("(ab){2}\\.(txt)"); // 只匹配abab.txt等cout<<boolalpha<<std::regex_match(strSrc, matchRes1, rePattern13)<<endl; // truecout<<matchRes1[0]<<":"<<matchRes1.str(1)<<":"<<matchRes1.str(2)<<endl;  // abab.txt:ab:txt// [abc]表示匹配字符集中的字符strSrc = "abcd.txt";std::regex rePattern14("[abc]\\.(txt)"); // 只匹配a.txt,b.txt,c.txtcout<<boolalpha<<std::regex_match(strSrc, matchRes1, rePattern14)<<endl; // flase// [abc]+表示匹配1个或多个字符集中的字符std::regex rePattern15("[abcde]+\\.(txt)"); // 只要.txt之前的字符属于字符集均匹配cout<<boolalpha<<std::regex_match(strSrc, matchRes1, rePattern15)<<endl; // truecout<<matchRes1[0]<<":"<<matchRes1.str(1)<<endl;  // abcd.txt:txt// 组([^aBcD]+)匹配到a即停止.[^aBcD]表示匹配非集合中的字符,[^A-Z]表示匹配A-Z之外的字符strSrc = "AbCdA23ab4.txt";std::regex rePattern16("([^aBcD]+)[^A-Z]+\\.(txt)"); // 只要.txt之前的字符属于字符集均匹配cout<<boolalpha<<std::regex_match(strSrc, matchRes1, rePattern16)<<endl; // truecout<<matchRes1[0]<<":"<<matchRes1.str(1)<<endl;  // AbCdA23ab4.txt:AbCdA23// [a-zA-Z0-9]{1,20},字符集内的字符,最少1次,最多20次.用来控制数字或字母的个数strSrc = "AbCdA23ab4t";std::regex rePattern17("[a-zA-Z0-9]{1,20}");cout<<boolalpha<<std::regex_match(strSrc, rePattern17)<<endl; // true// regex对象默认是大小写敏感的,regex::icase即指定大小写不敏感cout <<boolalpha<<regex_match("aaaAAA", regex("a*", regex::icase)) << endl;   // truecout <<boolalpha<<regex_match("aaaAAA", regex("a*")) << endl;              // falsereturn 0;
}

4.1. regex_search

#include "stdafx.h"
#include <regex>  // Must be included
#include <string>
#include <iostream>
using namespace std;int _tmain(int argc, _TCHAR* argv[])
{std::string strSrc = "Color is #ffAB11";// regex_serch并不要求整个匹配,只要匹配现有的pattern即为成功std::regex rePattern1("#([a-f]{2})");std::cout<<std::boolalpha<<std::regex_search(strSrc, rePattern1)<<std::endl;// smatch存放匹配的结果,索引0存放的是完整的结果,索引1存放的是第1个()表达式匹配的结果std::smatch matchRes2;std::regex rePattern2("#([a-f]{2})");std::cout<<std::boolalpha<<std::regex_search(strSrc, matchRes2, rePattern2)<<std::endl;cout<<matchRes2[0]<<":"<<matchRes2.str(1)<<endl;  // #ff:ff// [a-f]{2}表示有2个a-f之间的字符,[A-F]+表示有1个或多个A-F之间的字符std::smatch matchRes3;std::regex rePattern3("#([a-f]{2})([A-F]+)");std::cout<<std::boolalpha<<std::regex_search(strSrc, matchRes3, rePattern3)<<std::endl;cout<<matchRes3.str(0)<<":"<<matchRes3.str(1)<<":"<<matchRes3.str(2)<<endl;  // #ffAB:ff:ABcout<<matchRes3[0]<<":"<<matchRes3[1]<<":"<<matchRes3[2]<<endl;                 // #ffAB:ff:AB// prefix表示搜索匹配字符串之前未匹配的字符,suffix表示搜索匹配字符串之后未匹配的字符cout<<matchRes3.prefix()<<":"<<matchRes3.suffix()<<endl;                  // Color is:11// [0-9]*表示可以匹配0个或多个0-9的数字字符std::smatch matchRes4;std::regex rePattern4("#([a-f]{2})([A-F]+)([0-9]*)");std::cout<<std::boolalpha<<std::regex_search(strSrc, matchRes4, rePattern4)<<std::endl;cout<<matchRes4[0]<<":"<<matchRes4[1]<<":"<<matchRes4[2]<<":"<<matchRes4[3]<<endl;  // #ffAB11:ff:AB:11// prefix表示搜索匹配字符串之前未匹配的字符,suffix表示搜索匹配字符串之后未匹配的字符(此处为空,即没有剩余未匹配的字符)cout<<matchRes4.prefix()<<":"<<matchRes4.suffix()<<endl;                // Color is:// ^要求必须是从最开始即满足匹配std::regex rePattern5("^#([a-f]{2})([A-F]+)([0-9]*)");std::smatch matchRes5;std::cout<<std::boolalpha<<std::regex_search(strSrc, matchRes5, rePattern5)<<std::endl; // false// ^.+能够保证从最开始即满足匹配,$要求必须匹配到最后std::regex rePattern6("^.+#([a-f]{2})([A-F]+)([0-9]*)$");std::smatch matchRes6;std::cout<<std::boolalpha<<std::regex_search(strSrc, matchRes6, rePattern6)<<std::endl; // truereturn 0;
}

4.3. regex_replace

regex_replace要做两件事,首先是搜索匹配,然后将匹配到的字符按规则进行替换。

ECMAScript 扩展格式规则 替换的字符
“$&” 与整个正则表达式相匹配的字符序列
“$$” 直接替换$
“$`”(美元符号后跟反撇号) 与正则表达式相匹配的子序列之前的字符序列
“$’”(美元符号后跟正撇号) 与正则表达式相匹配的子序列之后的字符序列
“$n” 在 n 位置与捕获组相匹配的字符序列,其中 n 是介于 0 到 9 之间的数字
“$nn” 在 nn 位置与捕获组相匹配的字符序列,其中 nn 是介于 10 到 99 之间的数字
#include "stdafx.h"
#include <regex>  // Must be included
#include <string>
#include <iostream>
using namespace std;int _tmain(int argc, _TCHAR* argv[])
{std::string strSrc = "Color is #ffAB11";// 首先匹配所有的小写字母,然后将匹配的字符替换成指定字符*std::regex rePattern1("[a-z]");std::string strReplace1 = "*";std::cout<<std::tr1::regex_replace(strSrc, rePattern1, strReplace1)<<std::endl; // C**** ** #**AB11// $&表示匹配的字符,[$&]即替换为[匹配的字符]std::string strReplace2 = "[$&]";std::cout<<std::tr1::regex_replace(strSrc, rePattern1, strReplace2)<<std::endl; // C[o][l][o][r] [i][s] #[f][f]AB11// $1 $2 $3$4表示正则表达式中对应的4个捕获组(子表达式).匹配之后,按要求显示4个捕获组内容strSrc = "{0xff-0x11-0xab-0x21}";std::regex rePattern3("\\{([a-z0-9]+)-([a-z0-9]+)-([a-z0-9]+)-([a-z0-9]+)\\}");std::string strReplace3 = "$1 $2 $3$4";std::cout<<std::tr1::regex_replace(strSrc, rePattern3, strReplace3)<<std::endl; // 0xff 0x11 0xab0x21std::string strReplace4 = "$1 $3$4"; // 按格式显示1,3,4捕获组std::cout<<std::tr1::regex_replace(strSrc, rePattern3, strReplace4)<<std::endl; // 0xff 0xab0x21std::regex rePattern5("([a-z0-9]+)-([a-z0-9]+)-([a-z0-9]+)-([a-z0-9]+)");std::string strReplace5 = "$`"; // 将匹配的内容替换成prefixstd::string strReplace6 = "$'"; // 将匹配的内容替换成suffixstd::cout<<std::tr1::regex_replace(strSrc, rePattern5, strReplace5)<<std::endl; // {{}std::cout<<std::tr1::regex_replace(strSrc, rePattern5, strReplace6)<<std::endl; // {}}// 修改默认的flag参数为format_no_copy,即不拷贝prefix和suffixstd::cout<<std::tr1::regex_replace(strSrc, rePattern5, strReplace5, std::regex_constants::format_no_copy)<<std::endl; // {std::cout<<std::tr1::regex_replace(strSrc, rePattern5, strReplace6, std::regex_constants::format_no_copy)<<std::endl; // }return 0;
}

4.4 sregex_iterator

sregex_iterator按正则表达式循环匹配整个字符串,获取并存放所有匹配结果。

#include "stdafx.h"
#include <regex>  // Must be included
#include <string>
#include <iostream>
using namespace std;int _tmain(int argc, _TCHAR* argv[])
{std::string strDst = "Quick brown fox.";// 遍历整个字符串,匹配到空白时进入下一次匹配.匹配的结果存放在迭代器中std::regex rePattern("[^\\s]+");auto wordIt = std::sregex_iterator(strDst.begin(), strDst.end(), rePattern);// 计算迭代器中存放的正确匹配的数量std::cout<<"Found " << std::distance(wordIt, std::sregex_iterator())<<" words:\n";// 遍历迭代器显示结果for (; wordIt != std::sregex_iterator(); ++wordIt) {std::cout<<wordIt->str()<<std::endl;} strDst = "AB-12-AB AB-23-AC";// (\\D{2})表示2个非数字,(\\d{2})表示2个数字,(\\1)表示第1个捕获组即(\\D{2})的内容std::regex rePattern2("(\\D{2})-(\\d{2})-(\\1)");std::regex_iterator<std::string::const_iterator> begin(strDst.begin(), strDst.end(), rePattern2);for (auto iter = begin; iter != std::sregex_iterator(); iter++){std::cout<<iter->str()<<std::endl;}// out: AB-12-ABreturn 0;
}

4.5 sregex_token_iterator

sregex_token_iterator按正则表达式循环匹配整个字符串,获取满足token要求的匹配结果并存放,相较于regex_iterator提高了效率。

#include "stdafx.h"
#include <regex>  // Must be included
#include <string>
#include <iostream>
using namespace std;int _tmain(int argc, _TCHAR* argv[])
{std::string strDst = "Quick brown fox.";string data = "<person>\n"" <first>Nico</first>\n"" <last>Josuttis</last>\n""</person>\n";// \\1指定第1个捕获组,即第1个子表达式regex reg("<(.*)>(.*)</(\\1)>");// 0是默认值,即完整的匹配结果.1是匹配结果的第1个捕获组,2是匹配结果的第2个捕获组(子表达式)// iterate over all matches (using a regex_token_iterator):sregex_token_iterator pos(data.cbegin(),data.cend(), // sequencereg,                       // token separator0);      // 0:full match, 1:First substring, 2:second substringsregex_token_iterator end;for ( ; pos!=end ; ++pos ) {cout<<pos->str()<<endl;}// <first>Nico</first>// <last>Josuttis</last>// 第4个参数支持数组int arrSubMatch[] = {1, 2};sregex_token_iterator pos2(data.cbegin(),data.cend(), // sequencereg,                       // token separatorarrSubMatch);      // 0:full match, 1:First substring, 2:second substringsregex_token_iterator end;for ( ; pos2!=end ; ++pos2 ) {cout<<pos2->str()<<endl;}// first// Nico// last// Josuttis// -1指定显示匹配的prefix,即前面不匹配的string names = "nico, jim, helmut";regex sep("[ \t\n]*[,;.][ \t\n]*");  // separated by , ; or . and spacessregex_token_iterator iter(names.cbegin(),names.cend(),  // sequencesep,                          // separator-1);        // -1: values between separatorsfor ( ; iter != end; ++iter ) {cout <<*iter<<endl;}// nico// jim// helmutreturn 0;
}

4.6 regex_error

正则表达式一写错,就容易导致崩溃,所以针对一些由用户编写正则表达式的情况,需要添加异常处理,防止崩溃。

#include "stdafx.h"
#include <regex>  // Must be included
#include <string>
#include <iostream>
using namespace std;int _tmain(int argc, _TCHAR* argv[])
{try {// 正则表达式错误导致异常,需要捕获,否则会程序会崩溃std::regex re("[a-b][a");} catch (const std::regex_error& e) {std::cout << "regex error caught:"<< e.what() <<std::endl;if (e.code() == std::regex_constants::error_brack){std::cout << "The code was error!\n";}}return 0;
}

5. 其他

5.1. 分组

小括号来指定子表达式(也叫做分组),然后就可以指定这个子表达式的重复次数了。(\d{1,3}.){3}\d{1,3}是一个简单的IP地址匹配表达式。

5.2. 后向引用

使用小括号指定一个子表达式后,匹配这个子表达式的文本可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:以分组的左括号为标志,从左向右,第一个分组的组号为1,第二个为2,以此类推。
后向引用用于重复搜索前面某个分组匹配的文本。例如,\1代表分组1匹配的文本。

5.3. 分组及捕获

表达式 解释
(exp) 匹配exp,并捕获文本到自动命名的组里
(?exp) 匹配exp,并捕获文本到名称为name的组里
(?:exp) 匹配exp,不捕获匹配的文本
(?=exp) 匹配exp前面的位置
(?<=exp) 匹配exp后面的位置
(?!exp) 匹配后面跟的不是exp的位置
(?<!exp) 匹配前面不是exp的位置
(?#comment) 这种类型的组不对正则表达式的处理产生任何影响,只是为了提供让人阅读注释

5.4. 贪婪与懒惰

当正则表达式中包含能接受重复的量词(指定数量的代码,例如*,{5,12}等)时,通常的行为是匹配尽可能多的字符。考虑这个表达式:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。
有时需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的量词都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。如:a.?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab和ab。

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

C++11 regex库相关推荐

  1. c++11 regex 与 PCRE库使用

    c++11 regex 与 PCRE库使用 简介 PCRE C++11 regex 示例 pcre库捕获特殊字符串示例 c++11库捕获特殊字符串示例 正则支持对比 性能对比 源代码 简介 PCRE ...

  2. C/C++ 正则表达式 regex库介绍(详细版)

    文章目录 前言 一.总体观摩 1.纵观所有类 2.纵观所有函数 二.使用详解 1.使用前需要了解的东西 2.测试字符串 3.搜索子字符串 4.使用迭代器 5.替换字符串 6.分割字符串 7.异常处理 ...

  3. C++正则表达式regex库使用方法总结

    目录 一.regex库中常用组件介绍 二.regex库中常用组件使用 1.regex库组件使用准备 2.regex_match使用 3.regex_search使用 4.regex_replace使用 ...

  4. c++11 regex

    c++ regex 库,通过 #include <regex>来使用,是c++11标准引入的功能. regex 库提供三个最基本的正则表达式函数 regex_match -> 完全匹 ...

  5. c++11 regex 正则表达式验证车牌号

    在使用c++11 regex验证车牌号前,要首先明白有几个坑要踩: 1.车牌号校验规则,只有弄清楚了校验车牌号的规则才能写出正确的正则表达式,所以首先要弄清楚车牌号的校验规则. 2.c++11 中re ...

  6. 用Boost:regex库进行网页分析源代码【转】

    经过今天时间对bnoost的学习,特别是对regex 库的熟悉,完成了批量下载的boost.regex版(此前还有字符匹配+线程类版本,shell版本),功能很强,但如果需要完成具体任务,需要添加不少 ...

  7. Windows下用Mingw编译Boost.Regex库

    下载Boost库,解压. 定位到regex库文件夹下. GCC所对应的MAKEFILE为gcc.mak 进入命令提示符下,输入make -f gcc.mak 这是如果直接按回车执行的话,会出现错误: ...

  8. C++11 多线程库使用说明

    多线程基础 1.1 进程与线程 根本区别: 进程是操作系统资源分配的基本单位,线程是任务调度和执行的基本单位 开销方面: 每个进程都有自己独立的代码和数据空间,程序之间的切换开销较大. 线程可以看作是 ...

  9. C++11标准库 - array 1

    C++11标准库 - array std::array是原生数组的封装,它存放于栈上且大小固定,性能也与之相同.在原生数组的基础上,它添加了范围检查,以及其它的STL的相应特性,比如复制.交换.迭代器 ...

  10. 基于POSIX下REGEX库的文本URL过滤(C/C++语言)

    URL过滤报告 URL过滤需求分析: 输入为带中文.英文.标点符号.特殊符号等的字符串,输出也是字符串,但有以下要求: 1.把输入字符串中的网站URL(以"http://"开头). ...

最新文章

  1. 如何配置和部署安全的.NET三层应用
  2. @import和@class的区别
  3. 科技管理的第一个作业
  4. java 动态按钮_java-向片段动态添加按钮
  5. 图(Graph)的学习
  6. 吴恩达深度学习 —— 3.6 激活函数
  7. condition_variable的怪事
  8. Facebook广告投放有什么策略?
  9. 不能执行已释放 Script 的代码
  10. Linux终端显示图像
  11. 《四海小记c++学习之路》队列/银行叫号系统
  12. adb shell /system/bin/screencap screenrecord
  13. 某条微博评论数据爬取
  14. 中级微观经济学笔记整理
  15. bochs镜像java模拟器_【 bochs win7镜像完整版 】bochs win7镜像完整版(bochs win7 img文件)新版下载 - U大师...
  16. 无人车系统(一):运动学模型及其线性化
  17. unity3d 中能画出漂亮图案的函数之玫瑰图案
  18. C语言篇 - (1)初识C语言 - (1)什么是C语言
  19. EDID:识别和解决常见问题指南
  20. netty系列之:netty对http2消息的封装

热门文章

  1. 一个关于Schema的问题,请求帮助
  2. Json-getJSON
  3. 3.数据结构 --- 栈和队列
  4. 8.高性能MySQL --- 优化服务器设置
  5. 1.输入复制到输出,并将其中连续多个空格用一个空格代替
  6. 48.自定义邮件模板
  7. 4. HTML DOM Event 对象
  8. Elasticsearch Lucene 数据写入原理 | ES 核心篇
  9. 应用安全-安全设备-Waf系列-软Waf-D盾
  10. Python之路-4