C++与正则表达式入门 (5)

在上文中,为了从字符串中查找出所有匹配的字符,我们的做法是遍历原始字符串的每一个子字符串来进行查找,这样做很明显效率很低。更好的做法当然是使用迭代器。

正则表达式迭代器一共有四种,分别对应了是否是宽字符,是否是字符串类型:

类型 定义
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 匹配结果与分组

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wssgxf.html