例如,特殊字符-只有在字符组[...]内部才是元字符,否则它只能匹配普通的连字符符号。并且,即便在字符组内部,如果连字符是在开头,它依然是一个普通字符而不是表示一个范围。
相反的,问号?和点号.不在字符组内部的时候才是特殊字符。因此[?.]中的这两个符号仅仅代表这两个字符自身。
还有,字符^出现在字符组中的时候表示的是否定,例如:[a-z]和[^a-z]表示的是正好相反的字符集。但是当字符^不是用在字符组中的时候,它是一个,具体内容下文会说到。
量词的占有欲还是以content.txt的内容为基础,现在假设我们的目标是:找出所有双引号中的内容。
根据之前的知识,你可能很轻松就写出了下面这个正则表达式:
regex content_regex("\"(.+)\"");两边的双引号通过反斜杠转义
待捕获的内容通过圆括号形成分组
双引号中可以是任意内容,因此使用.+
但是当你运行程序的时候却发现它可能有点问题。它捕获的结果是:
"find" or "find and replace"为什么?其实很简单,因为双引号本身也可以与.匹配。上面这个正则表达式的含义是:匹配一个两端是双引号,中间是任意文字的内容。
当然,你马上想到一个改进方法那就是:将正则表达式圆括号中的.+改为[^"]+,它的含义是:一个或多个非双引号字符。这么做是可以的。但其实我们还有更好的做法。
我们再回头看一下原先的正则表达式,不考虑分组和转义,它可以写成:".+"。其实我们知道下面这三个字符串都是与其匹配的:
"find"
"find and replace"
"find" or "find and replace"
而将整个文本交给正则表达式的时候,它找出了最长的那个串。可见,原先的正则表达式太过“贪婪”(greedy)。是的,量词在默认情况都是贪婪的。即:它们会尽可能多的占有内容。
那我们能不能控制量词让其尽可能少的占有内容,只要满足匹配要求就可以呢?
答案是肯定的,而且做法很简单:在量词的后面加上一个?。即,将圆括号中.+修改为.+?即可。量词的默认形式称之为“匹配优先量词”,现在这种写法称之为“忽略优先量词”。
现在它找到的是下面两个匹配:
"find" "find and replace"小结一下:
匹配优先量词:*,+,?,{num, num}
忽略优先量词: *?,+?,??,{num, num}?
锚点锚点是一类特殊的标记,它们不会匹配任何文本内容,而是寻找特定的标记。你可以简单理解为它是原先表达式的基础上增加了新的匹配条件。如果条件不满足,则无法完成匹配。
锚点主要分为三种:
行/字符串的起始位置:^,行/字符串的结束位置:$
单词边界:\b
环视 ,见下文
例如:
正则表达式^\d+在字符串"123abc"中能找到匹配,在字符串"abc123"却找不到。
正则表达式some\b在字符串"some birds"中能找到匹配,在字符串"sometimes wonderful"中却找不到。
下面是代码示例:
#include <iostream> #include <regex> using namespace std; void findIn(const char* content, const char* reg_ex) { cout << "Search '" << reg_ex << "' in '" << content << "': "; smatch match; string s(content); regex reg(reg_ex); if(regex_search(s, match, reg)) { cout << match[0] << endl; } else { cout << "NOTHING" << endl; } } int main() { findIn("123abc", "^\\d+"); findIn("abc123", "^\\d+"); cout << endl; findIn("some birds", "some\\b"); findIn("sometimes wonderful", "some\\b"); return 0; }它的输出如下:
Search '^\d+' in '123abc': 123 Search '^\d+' in 'abc123': NOTHING Search 'some\b' in 'some birds': some Search 'some\b' in 'sometimes wonderful': NOTHING 环视现在假设我们有下面两个需求:
匹配出所有sometimes中的前四个字符“some”
匹配出所有的单词some,但是要排除掉“some birds”中的“some”
对于第一个问题,我们可以分两步:先找出所有的单词sometimes,然后取前四个字符。对于第二个问题,我们可以先找出所有的单词“some”,然后把后面是“birds”的丢掉。
以上的解法都是分两步完成。但实际上,借助环视(lookaround)我们可以一步就完成任务。
环视是对匹配位置的附加条件,只有条件满足时才能完成匹配。环视有:顺序(向右),逆序(向左),肯定和否定一共四种:
类型 正则表达式 匹配条件肯定顺序环视 (?=...) 子表达式能够匹配右侧文本
否定顺序环视 (?!...) 子表达式不能匹配右侧文本
肯定逆序环视 (?<=...) 子表达式能够匹配左侧文本
否定逆序环视 (?<!...) 子表达式不能匹配左侧文本
C++中的环视只支持顺序环视,不支持逆序环视。