正则表达式(regular expression)是一种描述字符序列的方法,是一种及其强大的计算工具。C++正则表达式库(RE库)定义在头文件regex中,包含多个组件:
regex | 表示有一个正则表达式的类,即regex类表示一个正则表达式 |
regex_match | 将一个字符序列与一个正则表达式匹配 |
regex_search | 寻求第一个与正则表达式匹配的子序列 |
regex_replace | 使用给定格式替换一个正则表达式 |
sregex_iterator | 迭代器适配器,调用regex_search来遍历一个string中所有匹配的子串 |
smatch | 容器类,保存在string中搜索的结果 |
ssub_match | string中匹配的子表达式的结果 |
注意:这些操作返回bool值,指出是否找到匹配 | |
(seq, m, r, mft) (seq, r, mft ) |
在字符序列seq中查找regex对象r中的正则表达式。seq可以是一个string、表示范围的一对迭代器以及一个指向空字符结尾的字符数组的指针 m是一个match对象,用来保存匹配结果的细节。m和seq必须具有兼容的类型 mft是一个可选的regex_constants::match_flag_type值。 |
使用正则表达式库
查找违反拼写规则“i除非在c之后,否则必须在e之前”的单词示例:
//查找不在字符c之后的字符串ei
string pattern("[^c]ei");
pattern = "[[:alpha:]]" + pattern + "[[:alpha:]]*";
regex r(pattern); //构造一个用于查找模式的regex
smatch results;
string test_str = "receipt freind theif receive";
if( regex_search(text_str, results, r))
cout << results.str() << endl;
我们首先定义了一个string来保存希望查找的正则表达式。正则表达式[^c]表明我们希望匹配任一不是'c'的字符,而[^c]ei指出我们想要匹配这种字符后接ie的字符串。此模式描述的字符串恰好包含三个字符。我们想要包含此模式的单词的完整内容。为了与整个单词匹配,我们还需要一个正则表达式与这个三字母模式之前和之后的字母匹配。
这个正则表达式包含0个或多个字母后接我们的三字母的模式,然后再接0个或多个额外的字母。默认情况下,regex使用的正则表达式语言是ECMAScript。在ECMAScript中,模式[[:alpha:]]匹配任一字母,符号+和*分别表示我们希望“1个或多个”或“0个或多个”匹配。因此[[::alpha:]]*将匹配0个或多个字母。
指定regex对象的选项
当我们定义一个regex或是对一个regex调用assign为其赋予新值时,可以指定一些标志来影响regex如何操作。这些标志控制regex对象的处理过程。对于指出编写正则表达式所用语言的6个标志,我们必须设置其中一个,且只能设置一个。默认情况下,ECMAScript标志被设置,从而regex会使用ECMA-262规范,这也是很多Web浏览器所用的正则表达式语言。
regex r(re) regex r(re, f) |
re表示一个正则表达式,它可以是一个string、一个表示字符范围的迭代对、一个指向空字符结尾的字符数组的指针、一个字符指针和一个计数器或是一个花括号包围的字符列表。 f是指出对象如何处理的标志。f通过下面列出的值来设置。如果未指定f,默认值为ECMAScript。 |
r1 = re | 将r1中的正则表达式替换成re。 re表示一个正则表达式,它可以是另一个regex对象、一个string、一个指向空字符结尾的字符数组的指针或是一个花括号包围的字符列表。 |
r1.assign(re, f) | 与使用赋值运算符(=)效果相同 |
r.mark_count() | r中子表达式的数目 |
r.flags() | 返回r的标志集 |
注:构造函数和赋值操作也可能抛出类型为regex_error的异常。 |
定义在regex和regex_constants::synatax_option_type中 | |
icase | 在匹配过程中忽略大小写 |
nosubs | 不保存匹配的子表达式 |
optimize | 执行速度优先于构造速度 |
ECMAScript | 使用ECMA-262指定的语法 |
basic | 使用POSIX基本的正则表达式语法 |
extended | 使用POSIX扩展的正则表达式语法 |
awk | 使用POSIX版本的awk语言的语法 |
grep | 使用POSIX版本的grep的语法 |
egrep | 使用POSIX版本的egrep的语法 |
一个正则表达式来识别扩展名的示例:
//1个或多个字母或数字字符后面接一个'.'再接"cpp"或"cxx"或"cc"
regex r("[[:alnum:]]+\\.{cpp|cxx|cc}$", regex::icase);
smatch results;
string filename;
while( cin >> filename)
if( regex_search(filename, results, r))
cout << results.str() << endl;
在正则表达式语言中,字符点(.)通常匹配任意字符。与C++一样,可以在字符之前放置一个反斜线\来去掉其特殊含义。由于反斜线\也是C++中的一个特殊字符,我们在字符串常量中必须连续使用两个反斜线。
一个正则表达式的语法是否正确是在运行时解析的。如果我们编写的正则表达式存在错误,则在运行时标准库会抛出一二类型为regex_error的异常。类似标准库异常类型,regex_error有一个描述发生什么错误的what操作,和一个返回错误类型对应的数值编码的code成员。
try{
regex r("[[:alnum:]+\\.(cpp|cxx|cc)$", regex::icase);
}catch (regex_error e)
{
cout << e.what() << "\ncode:" << e.code() << endl;
}