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. 正则表达式语法
正则表达式主要两部分构成,特殊字符和普通字符。
-
“.”: 匹配除"\n"之外的任何单个字符,若要匹配包括"\n"在内的任意字符,需使用诸如"[\s\S]"之类的模式;
-
“^”:匹配输入字符串的开始位置,不匹配任何字符,要匹配”^”字符本身,需使用”^”;
-
“$”:匹配输入字符串结尾的位置,不匹配任何字符,要匹配”$”字符本身,需使用”$”;
-
“*”: 零次或多次匹配前面的字符或子表达式,”*”等效于”{0,}”,如”^*b”可以匹配”b”、”^b”、”^^b”、…;
-
“+”: 一次或多次匹配前面的字符或子表达式,等效于”{1,}”,如”a+b”可以匹配”ab”、”aab”、”aaab”、…;
-
“?”: 零次或一次匹配前面的字符或子表达式,等效于”{0,1}”,如”a[cd]?”可以匹配”a”、”ac”、”ad”; 当此字符紧随任何其他限定符”*”、”+”、”?”、”{n}”、”{n,}”、”{n,m}”之后时,匹配模式是"非贪心的"。"非贪心的"模式匹配搜索到的、尽可能短的字符串,而默认的"贪心的"模式匹配搜索到的、尽可能长的字符串。如,在字符串"oooo"中,"o+?“只匹配单个"o”,而"o+“匹配所有"o”;
-
“|”:将两个匹配条件进行逻辑"或"(Or)运算,如正则表达式”(him|her)”匹配"itbelongs to him"和"it belongs to her",但是不能匹配"itbelongs to them.";
-
“\”: 将下一字符标记为特殊字符、文本、反向引用或八进制转义符,如,”n”匹配字符”n”,”\n”匹配换行符,序列”\”匹配”\”,”(“匹配”(“;
-
“\w”:匹配字母或数字或下划线,任意一个字母或数字或下划线,即A~Z,a~z,0~9,_中任意一个;
-
“\W”:匹配任意不是字母、数字、下划线的字符;
-
“\s”:匹配任意的空白符,包括空格、制表符、换页符等空白字符的其中任意一个,与”[ \f\n\r\t\v]”等效;
-
“\S”:匹配任意不是空白符的字符,与”[^\f\n\r\t\v]”等效;
-
“\d”:匹配数字,任意一个数字,0~9中的任意一个,等效于”[0-9]”;
-
“\D”:匹配任意非数字的字符,等效于”[^0-9]”;
-
“\b”: 匹配一个字边界,即字与空格间的位置,也就是单词和空格之间的位置,不匹配任何字符,如,“er\b"匹配"never"中的"er”,但不匹配"verb"中的"er";
-
“\B”: 非字边界匹配,“er\B"匹配"verb"中的"er”,但不匹配"never"中的"er";
-
“\f”:匹配一个换页符,等价于”\x0c”和”\cL”;
-
“\n”:匹配一个换行符,等价于”\x0a”和”\cJ”;
-
“\r”:匹配一个回车符,等价于”\x0d”和”\cM”;
-
“\t”:匹配一个制表符,等价于”\x09”和”\cI”;
-
“\v”:匹配一个垂直制表符,等价于”\x0b”和”\cK”;
-
“\cx”:匹配”x”指示的控制字符,如,\cM匹配Control-M或回车符,”x”的值必须在”A-Z”或”a-z”之间,如果不是这样,则假定c就是"c"字符本身;
-
“{n}”:”n”是非负整数,正好匹配n次,如,"o{2}"与"Bob"中的"o"不匹配,但与"food"中的两个"o"匹配;
-
“{n,}”:”n”是非负整数,至少匹配n次,如,"o{2,}“不匹配"Bob"中的"o”,而匹配"foooood"中的所有”o”,"o{1,}“等效于"o+”,"o{0,}“等效于"o*”;
-
“{n,m}”:”n”和”m”是非负整数,其中n<=m,匹配至少n次,至多m次,如,"o{1,3}"匹配"fooooood"中的头三个o,'o{0,1}‘等效于’o?’,注意,不能将空格插入逗号和数字之间;如”ba{1,3}”可以匹配”ba”或”baa”或”baaa”;
-
“x|y”:匹配”x”或”y”,如,”z|food”匹配"z"或"food";”(z|f)ood”匹配"zood"或"food";
-
“[xyz]”:字符集,匹配包含的任一字符,如,"[abc]“匹配"plain"中的"a”;
-
“[^xyz]””:反向字符集,匹配未包含的任何字符,匹配除了”xyz”以外的任意字符,如,"[^abc]“匹配"plain"中的"p”;
-
“[a-z]”:字符范围,匹配指定范围内的任何字符,如,"[a-z]"匹配"a"到"z"范围内的任何小写字母;
-
“[^a-z]”:反向范围字符,匹配不在指定的范围内的任何字符,如,"[^a-z]"匹配任何不在"a"到"z"范围内的任何字符;
-
“( )”:将”(“和”)”之间的表达式定义为”组”group,并且将匹配这个表达式的字符保存到一个临时区域,一个正则表达式中最多可以保存9个,它们可以用”\1”到”\9”的符号来引用;
-
“(pattern)”:匹配pattern并捕获该匹配的子表达式,可以使用$0…$9属性从结果”匹配”集合中检索捕获的匹配;"$0"表示整个匹配,"$1"表示第1个子表达式的匹配结果。当只有一个子表达式时两者可能是相同。
-
“(?:pattern)”:匹配pattern但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配,这对于用”or”字符” (|)”组合模式部件的情况很有用, 如,”industr(?:y|ies)”是比”industry|industries”更简略的表达式;
-
“(?=pattern)”: 非获取匹配,正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。如,“Windows(?=95|98|NT|2000)“能匹配"Windows2000"中的"Windows”,但不能匹配"Windows3.1"中的"Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始;
-
“(?!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; // true
std::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; // true
std::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; // true
cout<<matchRes1[0]<<":"<<matchRes1[1]<<endl; // foot.txt:foot
std::regex rePattern6("(....)\\.txt"); // \\.使用转义字符
cout<<boolalpha<<std::regex_match(strSrc, matchRes1, rePattern6)<<endl; // true
cout<<matchRes1[0]<<":"<<matchRes1[1]<<endl; // foot.txt:foot
cout<<matchRes1[0]<<":"<<matchRes1.str(1)<<endl; // foot.txt:foot
std::ssub_match ssMatch = matchRes1[1];
// ssMatch支持强制转换成string类型,和ssMatch.str()等价
cout<<matchRes1[0]<<":"<<ssMatch<<endl; // foot.txt:foot
cout<<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; // true
cout<<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; // true
cout<<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; // true
cout<<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; // true
cout<<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.txt
cout<<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; // true
cout<<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; // true
cout<<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; // true
cout <<boolalpha<<regex_match("aaaAAA", regex("a*")) << endl; // false
return 0;
}
4.2. 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:AB
cout<<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; // true
return 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 0xab0x21
std::string strReplace4 = "$1 $3$4"; // 按格式显示1,3,4捕获组
std::cout<<std::tr1::regex_replace(strSrc, rePattern3, strReplace4)<<std::endl; // 0xff 0xab0x21
std::regex rePattern5("([a-z0-9]+)-([a-z0-9]+)-([a-z0-9]+)-([a-z0-9]+)");
std::string strReplace5 = "$`"; // 将匹配的内容替换成prefix
std::string strReplace6 = "$'"; // 将匹配的内容替换成suffix
std::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和suffix
std::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-AB
return 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(), // sequence
reg, // token separator
0); // 0:full match, 1:First substring, 2:second substring
sregex_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(), // sequence
reg, // token separator
arrSubMatch); // 0:full match, 1:First substring, 2:second substring
sregex_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 spaces
sregex_token_iterator iter(names.cbegin(),names.cend(), // sequence
sep, // separator
-1); // -1: values between separators
for ( ; iter != end; ++iter )
{
cout <<*iter<<endl;
}
// nico
// jim
// helmut
return 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次以上,但尽可能少重复 |