IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ std::regex | 正则表达式 -> 正文阅读

[C++知识库]C++ std::regex | 正则表达式

cppreference: https://zh.cppreference.com/w/cpp/regex
结合以下网站食用更加:


一、正则表达式的操作

  • 目标序列:被正则表达式搜索的目标序列。可以是二个迭代器所指定的范围、空终止字符串或一个 std::string 。
  • 模式:即正则表达式。使用正则特定语法的字符串构成的 std::basic_regex 类型对象
    受支持的语法变体的描述见 syntax_option_type(定义一些匹配规则,如不区分大小写等) 。
  • 匹配的结果集:关于匹配的信息使用 std::match_results 类型对象获取。
  • 替换字符串:将匹配到的字符替换。受支持的语法变体的描述见 match_flag_type

简单示例:

#include <iostream>
#include <iterator>
#include <string>
#include <regex>
using namespace std;

int main()
{
    // 目标序列
    string s = "Some people, when confronted with a problem, think ";

    // 结果集
    smatch result;

    // 模式串
    regex reg("(\\w{5,})"); /* 5个以上的长单词 */

    // 匹配
    regex_search(s, result, reg);  // 只匹配一个结果
    cout << result[0] << endl;

    // 利用迭代器,反复匹配达到全局(\g)匹配的效果
    for (sregex_iterator it(s.begin(), s.end(), reg), end_it; it != end_it; ++it)
    {
        cout << it->str() << " ";
    }
    cout << endl;

 	// 或者使用循环的方式,多次调用regex_search
    while (regex_search(s, result, reg))
    {
        std::cout << result.str() << " ";
        s = result.suffix(); 
    }
    cout << endl;
}

输出结果:
在这里插入图片描述

二、主要的几个类

这些类封装正则表达式和在字符的目标序列中匹配正则表达式的结果。

2.1 basic_regex 正则表达式对象

用于构建正则对象。

类型别名:

  • regex == basic_regex
示例:

regex reg("") 构建用于匹配正则的表达式。

    string s = "This is a simple example";
    regex reg("(simple)");
    string new_s = regex_replace(s, reg, "[$&]");
    cout << new_s << '\n'; // This is a [simple] example

2.2 match_results 正则匹配结果集

std::match_results 保有表示正则表达式匹配结果的字符序列汇集。

类型别名:

  • std::cmatch == std::match_results<const char*>
  • std::smatch == std::match_results<std::string::const_iterator>

该类型从std::regex_iterator 获得,或通过 std::regex_search 或 std::regex_match 修改(传参后回写)。

std::match_results 保有 std::sub_match ,它们每个都是一对指向匹配的原初字符序列中的迭代器,故若原初字符序列被销毁,或指向它的迭代器因另外的原因非法化,则检验 std::match_results 是未定义行为。

示例:

用法:

smatch result;		// string类型的mattch
regex_search(s, result, reg);	// 匹配
regex_match(s, result, reg);	// 完全匹配

有关match_results 成员变量:https://zh.cppreference.com/w/cpp/regex/match_results

match_results成员函数

    string s = "This is a simple example";  /* 目标序列 */
    smatch result;          /* 结果集 */
    regex reg("(\\w{5,})"); /* 模式串 */

    regex_search(s, result, reg);  
    cout << "regex_search(s, result, reg)\n";
    cout << "\n状态:";
    cout << "\n-- 检查结果是否合法(合法为 true)               result.ready()    = " << result.ready();
    cout << "\n\n大小:";
    cout << "\n-- 检查匹配是否成功(失败匹配则为 true)         result.empty()    = " << result.empty();
    cout << "\n-- 返回完全建立的结果状态中的匹配数            result.size()     = " << result.size();
    cout << "\n-- 返回子匹配的最大可能数量                    result.max_size() = " << result.max_size();
    cout << "\n\n元素访问:";
    cout << "\n-- 返回特定子匹配的长度                        result.length()   = " << result.length();
    cout << "\n-- 返回特定子匹配首字符的位置                  result.position() = " << result.position();
    cout << "\n-- 返回特定子匹配的字符序列                    result.str()      = " << result.str();
    cout << "\n-- 返回指定的子匹配                            result[0]         = " << result[0];
    cout << "\n-- 返回目标序列起始和完整匹配起始之间的子序列  result.prefix()   = " << result.prefix();
    cout << "\n-- 返回完整匹配结尾和目标序列结尾之间的子序列  result.suffix()   = " << result.suffix();
    cout << "\n\n迭代器:";
    cout << "\n--返回指向子匹配列表起始的迭代器      result.begin()/cbegin()";
    cout << "\n--返回指向子匹配列表末尾的迭代器      result.end()/cend()";
    cout << "\n\n其他:";
    cout << "\n--为输出格式化匹配结果                result.format";
    cout << "\n--交换内容                            result.swap()";

在这里插入图片描述
如果regex_search(s, result, reg);匹配失败,size为0,empty为true。
在这里插入图片描述

并且通过上述输出可知,result 的size即使为0,仍然可以通过下标访问其元素(下标返回的对象类型是sub_match)。

    regex_search(s, result, reg);
    cout << result.size() << "\n";		// 匹配到的个数
    cout << result[0].matched << "\n";	// 匹配是否成功,返回bool

通过VS 调试窗口可以证实这一点(match_results 内部由 sub_match组成)
在这里插入图片描述

2.3 sub_match 匹配项match_results的 一部分

sub_match 的实例作为 std::match_results 容器的一部分正常构造并移居。

类型别名:

  • csub_match == sub_match<const char*>
  • ssub_match == sub_match<std::string::const_iterator>

该对象继承自std::pair,first保存子表达式匹配序列的开始,second保存匹配序列的结尾后一位置。

  • length 若存在则返回匹配的长度
  • str 转换为底层字符串类型
  • compare 若存在则比较匹配的子序列
示例:
    regex_search(s, result, reg);

    // 输出类型信息
    cout << typeid(result.str()).name() << "\n";   //  std::basic_string
    cout << typeid(result[0]).name() << "\n";   //  std::sub_match

    for (ssub_match sub : result)   // 遍历所有结果
    {
        cout << "是否匹配成功:" << sub.matched << "\n";
        cout << "匹配到的内容:" << sub.str() << "\n";
        cout << "匹配到的长度:" << sub.length() << "\n";
        cout << sub.compare("simple") << "\n";  // 等价于string::compare. 返回 -1,0,1
    }

在这里插入图片描述

三、算法

这些算法将封装于 regex 的正则表达式应用到字符的目标序列。

match_result 中所含的首个 sub_match (下标 0 )始终表示 regex 所做的目标序列内的完整匹配,而后继的 sub_match 表示按顺序对应分隔正则表达式中子表达式的左括号的子表达式匹配

regex_match 完整匹配

尝试匹配一个正则表达式到整个字符序列

在这里插入图片描述

示例:
    string ss[] = { "foo.txt", "bar.txt", "baz.dat", "zoidberg" };

    // 提取几个子匹配
    regex reg("([a-z]+)\\.([a-z]+)");  // 匹配xxx.xxx 格式的字符串
    smatch result;

    for (const auto& s : ss) {
        if (regex_match(s, result, reg)) {
            cout << s << '\n';
            for (size_t i = 0; i < result.size(); ++i) {
                ssub_match sub_match = result[i];
                string piece = sub_match.str();
                cout << "  submatch " << i << ": " << piece << '\n';
            }
        }
    }

在这里插入图片描述
注意这里每个匹配项输出了3个,其中result[0]是完整匹配,其他是匹配成功后根据(进行分组的项。

regex_search 任意部分匹配

尝试匹配一个正则表达式到字符序列的任何部分
在这里插入图片描述

示例:
    string log(R"(
        Speed:	366
        Mass:	35
        Speed:	378
        Mass:	32
        Speed:	400
	    Mass:	30)");

    regex reg(R"(Speed:\t\d*)");
    smatch sm;
    while (regex_search(log, sm, reg))
    {
        cout << sm.str() << '\n';
        log = sm.suffix();  // sm.suffix() 是剩余的字符串
    }

在这里插入图片描述

    // C 风格字符串演示
    cmatch cm;
    if (regex_search("this is a test", cm, regex("test")))
        cout << "\nFound " << cm[0] << " at position " << cm.prefix().length();
// Found test at position 10

regex_match 与 regex_search 区别

  • regex_match 只考虑完全匹配,只有目标串与模式串完全匹配才会返回True,并将结果集回填到 result 中。
  • regex_search 只要匹配到重合部分,就判定为匹配成功。
示例:
regex re("Get|GetValue");
cmatch m;
regex_search("GetValue", m, re);  // 返回 true ,且 m[0] 含 "Get"
regex_match ("GetValue", m, re);  // 返回 true ,且 m[0] 含 "GetValue"
regex_search("GetValues", m, re); // 返回 true ,且 m[0] 含 "Get"
regex_match ("GetValues", m, re); // 返回 false

上述 regex_match 匹配时,模式串为 Get 或 GetValue。 进行正则匹配时:
GetValues,或 GetValues 都只匹配到整个单词的一部分,因此是不完全匹配,regex_match 认为是匹配失败。

而 regex_search 只要匹配到单词的一部分,就算匹配成功。

regex_replace 替换

以格式化的替换文本来替换正则表达式匹配的出现位置

int main()
{
   string text = "Quick brown fox";
   regex vowel_re("a|e|i|o|u");
 
   // 写结果到输出迭代器
   regex_replace(ostreambuf_iterator<char>(cout),
                      text.begin(), text.end(), vowel_re, "*");
 
   // 构造保有结果的字符串
   cout << '\n' << regex_replace(text, vowel_re, "[$&]") << '\n';
}

迭代器

regex_iterator 用于遍历在序列中找到的匹配正则表达式的整个集合。

regex_iterator 全局匹配(匹配多个)

迭代一个字符序列中的所有正则表达式匹配。

类型别名:

  • cregex_iterator == regex_iterator<const char*>
  • sregex_iterator == regex_iterator<std::string::const_iterator>
示例:

使用 regex_iterator 创建的迭代器,会自动进行正则匹配,并在 ++ 操作时,从上一次匹配到的位置继续进行正则匹配。

    const string s = "This is a simple example.";

    regex reg("[^\\s]+");   // 匹配单词
    auto words_begin = sregex_iterator(s.begin(), s.end(), reg);
    auto words_end = sregex_iterator();

    cout << "size =  " << distance(words_begin, words_end);

    for (sregex_iterator i = words_begin; i != words_end; ++i) {
        cout <<  i->str() << " ";
    }
    cout << endl;

    /* 输出
        size =  5
        This is a simple example.
    */
regex_token_iterator

迭代给定字符串中的所有正则表达式匹配中的指定子表达式,或迭代未匹配的子字符串

示例:反向匹配正则

注意 sregex_token_iterator 最后一个参数,表示第几组。

当最后一个参数为 -1 时,则结果集中保存所有不匹配正则表达式的部分,类似 split 函数切割字符串。

    const string s = "This_is_a_simple_example.";

    regex reg("_+");   // 匹配下划线
    auto words_begin = sregex_token_iterator(s.begin(), s.end(), reg, -1);
    auto words_end = sregex_token_iterator();

    cout << "size =  " << distance(words_begin, words_end) << "\n";

    for (sregex_token_iterator i = words_begin; i != words_end; ++i) {
        cout <<  i->str() << " ";
    }
    cout << endl;

    /* 输出
        size =  5
        This is a simple example.
    */
示例:分组匹配

第四个参数如果不填,默认为 0, 等同于不分组。

// 正则reg中,一个封闭`(`视为一个分组 
regex reg("_+");   // 不加括号,没有分组
regex reg("(_+)");   // 有括号,只有一个分组
  • 对于没有分组的,sregex_token_iterator(s.begin(), s.end(), reg); 第四个参数需要不填,或填为0 才能匹配到 reg。
  • 对于有有分组的:
    • 参数为 0,匹配所有分组
    • 参数为1,匹配第一个分组
    • 参数为2,匹配第二个分组
    • 参数为n,如果分组不足n,则不匹配
    • 参数为-1,则匹配与reg相反的。

参考下列示例:

   const string s = "foo.txt, bar.txt, baz.dat, zoidberg";

   regex reg("([a-z]+)\\.([a-z]+)");   // 两个分组,匹配 xxx.xxx 格式

   using reg_iter = sregex_token_iterator;

   cout << "is -1 :  ";
   for (auto i = reg_iter(s.begin(), s.end(), reg, -1); i != reg_iter(); ++i) {
       cout << i->str() << " ";
   }

   cout << "\nis  0 :  ";
   for (auto i = reg_iter(s.begin(), s.end(), reg, 0); i != reg_iter(); ++i) {
       cout << i->str() << " ";
   }

   cout << "\nis  1 :  ";
   for (auto i = reg_iter(s.begin(), s.end(), reg, 1); i != reg_iter(); ++i) {
       cout << i->str() << " ";
   }

   cout << "\nis  2 :  ";
   for (auto i = reg_iter(s.begin(), s.end(), reg, 2); i != reg_iter(); ++i) {
       cout << i->str() << " ";
   }

   cout << "\nis  3 :  ";
   for (auto i = reg_iter(s.begin(), s.end(), reg, 3); i != reg_iter(); ++i) {
       cout << i->str() << " ";
   }

在这里插入图片描述

四、其他

异常:

  • 此类定义作为异常抛出以报告来自正则表达式库错误的类型。
  • regex_error 报告正则表达式库生成的错误

特征:

  • regex_traits 类用于封装 regex 的本地化方面。
  • regex_traits 提供正则表达式库所需的关于字符类型的元信息

常量

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 15:59:31  更:2022-04-06 16:03:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:55:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码