在上文中,为了从字符串中查找出所有匹配的字符,我们的做法是遍历原始字符串的每一个子字符串来进行查找,这样做很明显效率很低。更好的做法当然是使用迭代器。
正则表达式迭代器一共有四种,分别对应了是否是宽字符,是否是字符串类型:
类型 定义cregex_iterator regex_iterator<const char*>
wcregex_iterator regex_iterator<const wchar_t*>
sregex_iterator regex_iteratorstd::string::const_iterator
wsregex_iterator regex_iteratorstd::wstring::const_iterator
在一大段文本中查找所有匹配的目标,这是一个非常常见的需求。而迭代器正好满足这一需求,它会依次返回它从文本中找到的匹配内容。
示例:统计出文本中一共出现了多个单词。
思路:组成单词的字母可以使用[[:alpha:]]字符类来表达,一个单词至少有一个字母,因此这个正则表达式可以写成:[[:alpha:]]+。然后借助迭代器便可以统计出总数量。
代码示例如下:
#include <fstream> #include <iostream> #include <regex> using namespace std; int main() { regex word_regex("[[:alpha:]]+"); // ① ifstream file("./content.txt"); // ② string line; int word_count = 0; while(getline(file, line)) { // ③ auto iter_begin = sregex_iterator(line.begin(), line.end(), word_regex); // ④ auto iter_end = sregex_iterator(); // ⑤ for (auto iter = iter_begin; iter != iter_end; iter++) { // ⑥ word_count++; // ⑦ // cout << iter->str() << endl; // ⑧ } } cout << "It contains " << word_count << " words" << endl; // ⑨ return 0; }这段代码的说明如下:
匹配单词的正则表达式
通过ifstream读取文本文件
依次读取文本文件中的每一行
通过正则表达式迭代器从文本行的逐个匹配
迭代器的末尾
迭代器遍历
每遇到一个匹配进行一次计数
如果需要,可以输出匹配的内容
这段代码输出如下:
It contains 153 words接下来的几个代码示例的主体结构和这里会很相似,我们总是先打开文本文件,然后读取每一行来进行处理。
正则表达式选项前面的示例中我们已经看到,通过std::regex并传递字符串就可以构造正则表达式对象。实际上,除了std::regex,还有宽字符版本的std::wregex。它们都源自std::basic_regex
类型 定义regex basic_regex
wregex basic_regex<wchar_t>
在创建正则表达式对象的时候,除了描述规则本身的字符串之外,还可以传递一个flag_type类型的参数,该参数的值定义在std::regex_constants::syntax_option_type中。它们中与相关的已经在上文介绍过了。
剩下的还有几个说明如下:
值 效果icase 以不考虑大小写进行字符匹配。
nosubs 进行匹配时,将所有被标记的子表达式 exprexpr 当做非标记的子表达式 ?:expr?:expr 。不将匹配存储于提供的 std::regex_match 结构中,且 mark_count() 为零
optimize 指示正则表达式引擎进行更快的匹配,带有令构造变慢的潜在开销。例如这可能表示将非确定 FSA 转换为确定 FSA 。
collate 形如 “[a-b]” 的字符范围将对本地环境敏感。
multiline(C++17) 若选择 ECMAScript 引擎,则指定^匹配行首,$应该匹配行尾。
这其中,第一个是我们最常用的。
示例:匹配文本中“regular expression”所有的单复数,并且不区分大小写。
思路:单词的首字母有些会大写,我们可以通过[Rr]来匹配大写或者小写的R字母,但实际上,使用icase无疑会更方便。
代码示例:
#include <fstream> #include <iostream> #include <regex> using namespace std; int main() { regex word_regex("regular expressions?", regex::icase); ifstream file("./content.txt"); string line; while(getline(file, line)) { auto iter_begin = sregex_iterator(line.begin(), line.end(), word_regex); auto iter_end = sregex_iterator(); for (auto iter = iter_begin; iter != iter_end; iter++) { cout << iter->str() << endl; } } return 0; }这段代码与前面的结构是一样的,我们最需要关注的可能就是下面这一行:
regex word_regex("regular expressions?", regex::icase);通过std::regex::icase我们指定了这个正则表达式是不区分大小写的。
另外还有一个值得注意的就是正则表达式末尾的...s?,它意味着单词可能是单数或者复数,因此结尾的“s”可以出现0次或者1次。
这段代码输出如下:
regular expression regular expressions Regular expressions 匹配结果与分组