文章目录

  • 前言
  • 一、总体观摩
    • 1.纵观所有类
    • 2.纵观所有函数
  • 二、使用详解
    • 1.使用前需要了解的东西
    • 2.测试字符串
    • 3.搜索子字符串
    • 4.使用迭代器
    • 5.替换字符串
    • 6.分割字符串
    • 7.异常处理
  • 三、封装成类

前言

对学习C/C++感兴趣的同学可以看看这篇文章哦:C/C++教程

从C++11开始,C++开始支持正则表达式的使用,用于匹配字符串时非常方便!(比如从爬取的网页源码中提取指定的字符串匹配用户输入邮箱是否为正确格式替换一篇文章中指定的所有字符串

但正如大家所看到的,C++一如既往的使用模板实现,以至于我们使用的时候,如果出错了,很难看明白到底哪里出错了

所以本文对C++正则表达式库进行详细解析,便于大家的使用!

一、总体观摩

正则表达式库为regex,使用C++11及以上即可正常使用

#include<regex>

1.纵观所有类

regex文件里总共有7个模板类以及若干实例化的类

模板类 实例化类 用途
basic_regex regex:实际为basic_regex<char>,wregex:实际为basic_regex<wchar_t>,下面的类似,不再一一详细说明 作为正则表达式对象,用于匹配文本
match_results cmatchwcmatchsmatchwsmatch 用于获得匹配到的结果,实际可以看作sub_match的数组
sub_match csub_match,wcsub_match ,ssub_match ,wssub_match 保存捕获组,一般直接用match_result数组访问的方式直接调用,所以一般看不到它
regex_iterator cregex_iterator,wcregex_iterator,sregex_iterator,wsregex_iterator 用于遍历结果或子匹配的迭代器
regex_token_iterator cregex_token_iteratorwcregex_token_iteratorsregex_token_iteratorwsregex_token_iterator 用于遍历未匹配部分的迭代器
regex_error 报告正则表达式库生成的错误
regex_traits 描述用于匹配的元素的特征。一般用不上,有需求的可参考官方文档

虽然看着挺多,但其实平时真正用到的只有少数几个

特别需要注意的是,上面的类都是分类别配对使用的,比如:

regex ,cmatch,csub_match,cregex_iterator

就是一组

或者

regex ,smatch,ssub_match,sregex_iterator

也是一组

可以总结出的规律有:

  • 前缀没有w字母的为操作多字节字符,添加了w的则为操作宽字节字符
  • 前缀有c的,代表是操作char*类型字符串
  • 前缀有s的,代表是操作string类型字符串

注意,char*类型字符串与string类型实现类之间不能混用,否则会出错!

2.纵观所有函数

函数 用途
regex_match 匹配指定字符串整体是否符合
regex_search 匹配字符串中符合的子字符串
regex_replace 替换字符串中指定的字符串

二、使用详解

如何写正则表达式就不做细说,网上有很多教程,只对函数如何使用作出详细介绍

1.使用前需要了解的东西

下图为regex库默认使用的ECMAScript文法的表达式

如果想要更改为其它文法,只需要在regex构造函数中最后一位填入对应文法即可,例如:

regex r("<.*?>(.*)<.*?>", regex_constants::grep);

当然除了选择文法,还可以选择其它标志,只需要将他们用符号 | 连接起来即可

如忽略大小写匹配可以写为

regex r("<.*?>(.*)<.*?>", regex_constants::grep|regex_constants::icase);

可以看到,其实这些可选项都在regex_constants中,还有其它可选项如下:

不同文法之间的差异

还需要注意的是,C++中许多字符需要添加\ 符号进行转义才能使用,过于麻烦,所以C++11之后,出现了如下写法:

R"dem(内容)dem"

使用该写法就可以不再转义即可使用,其中dem为任意字符,但要求前后一致即可,其它为固定写法

2.测试字符串

该功能用到regex_match 函数

一般来说,最常用的就是下面这种写法:

比如测试用户输入字符串是否包含@符号:

regex r(".*@.*");
string str;
cin >> str;
if (regex_match(str, r)) {cout << "匹配成功";
}
else {cout << "匹配失败";
}

3.搜索子字符串

该功能用到regex_search函数

一般用法肯定是找出一段文本中所需要的子字符串,用法如下

     string sStr; //要进行匹配的字符串std::string::const_iterator begin = sStr.begin(); //开始迭代器std::string::const_iterator end = sStr.end(); //结束迭代器std::smatch m; //匹配的结果regex r; //正则表达式while (std::regex_search(begin, end, m, r)) {begin = m[0].second; //更新开始迭代器的位置m[n].str(); //获得第n个捕获组,其中0表示匹配到的全部子字符串}

该代码段就是不断从sStr中匹配符合r的子字符串,匹配成功则返回true,并将匹配到的结果放在m中,可通过m[n].str()方式返回指定捕获组的子字符串

同时m[0].second记录了当前匹配到的位置,所以通过它更新begin ,就可以遍历所有子字符串,直到无法匹配,返回false,结束

4.使用迭代器

如果你认为regex_search用起来比较麻烦,则可以使用迭代器,用法如下:

 regex r("-(.*?)-");string s = "yushi-csdn--yushi-csdn";sregex_iterator beg(s.begin(),s.end(),r);sregex_iterator end;for (; beg != end; beg++) {cout << beg->str(1) << endl;}

由于sregex_iterator 默认构造函数为指向最后一个元素之后,所以对end没有进行任何处理,只是作为一个结束标志

成员函数str可以返回指定捕获组的字符串,不传入数字则代表全部匹配内容

5.替换字符串

该功能用到regex_replace函数

string sStr; //要进行匹配的源字符串
regex r; //正则表达式
string toReplace; //进行替换的字符串
string ret=regex_replace(sStr, r, toReplace)

该函数就是将sStr中匹配符合r的子字符串,将其全部替换为toReplace,并将结果返回到ret中

小技巧:可以在toReplace添加$n,n代表着第几个捕获组,可用于格式化字符串,总结如下:

6.分割字符串

这里主要使用到了sregex_token_iterator

 regex r("-"); //以-为分隔符string s = "yushi-csdn-yushi-csdn";sregex_token_iterator beg(s.begin(), s.end(), r,-1); //传入-1,代表对匹配到的分隔符之间的内容感兴趣sregex_token_iterator end; //结束标志for (; beg != end; beg++) {cout << beg->str() << endl;}

用法基本于上述迭代器用法一样

唯一需要注意的是最后传入的那个-1,代表着我想要的是匹配项之间的内容

7.异常处理

regex库里已经实现了异常类regex_error ,直接使用即可,what函数将返回错误信息

 try{regex r("\{\}");}catch (const std::regex_error & e){cout << e.what()<<endl;}

上述正则表达式使用grep语法,将{}进行转义,将输出以下错误:

regex_error(error_badrepeat): One of *?+{ was not preceded by a valid regular expression.

三、封装成类

可以看出来,原库函数使用起来很不方便,所以我花了点时间将上述几种常用功能封装成类,方便使用

#include<regex>
#include<list>
#include<string>
class SRegex {private:std::regex r;std::wregex wr;SRegex(const SRegex& r) = delete;
public:SRegex() {}/*** @brief 多字节字符构造函数* @param pattern 匹配模式*/SRegex(const std::string& pattern) {r = pattern;}/*** @brief 宽字节字符构造函数* @param pattern 匹配模式*/SRegex(const std::wstring& pattern) {wr = pattern;}/*** @brief (多字节)重新设置匹配模式* @param pattern 匹配模式*/void SetPattern(const std::string& pattern) {r = pattern;}/*** @brief (宽字节)重新设置匹配模式* @param pattern 匹配模式*/void SetPattern(const std::wstring& pattern) {wr = pattern;}/*** @brief 测试源字符串是否满足匹配模式(多字符)* @param sStr 源字符串* @return 匹配返回true,否则返回false*/bool IsMatch(const std::string& sStr) {return std::regex_match(sStr, r);}/*** @brief 测试源字符串是否满足匹配模式(宽字符)* @param sWStr 源字符串* @return 匹配返回true,否则返回false*/bool IsMatch(const std::wstring& swStr) {return std::regex_match(swStr, wr);}/*** @brief 获得所有满足匹配模式的子字符串(多字节字符)* @param res 获得匹配到的结果* @param sStr 源字符串* @param index 获取指定捕获组,默认为0,即全部* @return 存在返回true,否则返回false*/bool GetSubStr(std::list<std::string>& res, const std::string& sStr, int index = 0) {res.clear();std::string::const_iterator begin = sStr.begin();std::string::const_iterator end = sStr.end();std::smatch m;while (std::regex_search(begin, end, m, r)) {begin = m[0].second;res.push_back(std::move(m[index].str()));}return !res.empty();}/*** @brief 获得所有满足匹配模式的子字符串(宽字符)* @param res 获得匹配到的结果* @param sStr 源字符串* @param index 获取指定捕获组,默认为0,即全部* @return 存在返回true,否则返回false*/bool GetSubStr(std::list<std::wstring>& res, const std::wstring& sStr, int index = 0) {res.clear();std::wstring::const_iterator begin = sStr.begin();std::wstring::const_iterator end = sStr.end();std::wsmatch m;while (std::regex_search(begin, end, m, wr)) {res.push_back(std::move(m[index].str()));}return !res.empty();}/*** @brief 特换匹配到的子字符串(多字节)* @param sStr 源字符串* @param toReplace 将要进行替换的字符串* @return 返回替换成功的字符串*/std::string Replace(const std::string& sStr, const std::string& toReplace) {return std::move(std::regex_replace(sStr, r, toReplace));}/*** @brief 特换匹配到的子字符串(宽字节)* @param sStr 源字符串* @param toReplace 将要进行替换的字符串* @return 返回替换成功的字符串*/std::wstring Replace(const std::wstring& sStr, const std::wstring& toReplace) {return std::move(std::regex_replace(sStr, wr, toReplace));}/*** @brief 分割字符串(多字节)* @param sStr 需要进行分割的源字符串* @return 返回分割后的字符串链表*/std::list<std::string> Split(const std::string& sStr) {std::sregex_token_iterator beg(sStr.begin(), sStr.end(), r, -1);std::sregex_token_iterator end;std::list<std::string> res;for (; beg != end; beg++) {res.push_back(std::move(beg->str()));}return std::move(res);}/*** @brief 分割字符串(宽字节节)* @param sStr 需要进行分割的源字符串* @return 返回分割后的字符串链表*/std::list<std::wstring> Split(const std::wstring& sStr) {std::wsregex_token_iterator beg(sStr.begin(), sStr.end(), wr, -1);std::wsregex_token_iterator end;std::list<std::wstring> res;for (; beg != end; beg++) {res.push_back(std::move(beg->str()));}return std::move(res);}
};

因为我测试数据不多,可能存在bug,欢迎在评论区指出,我会及时更正,

C/C++ 正则表达式 regex库介绍(详细版)相关推荐

  1. C++正则表达式regex库使用方法总结

    目录 一.regex库中常用组件介绍 二.regex库中常用组件使用 1.regex库组件使用准备 2.regex_match使用 3.regex_search使用 4.regex_replace使用 ...

  2. 中正则表达式详解_python :正则表达式/re库 超级详细de注释解释

    首先要解释,什么是正则表达式: 给定一串字符串,我们可以提取他的特征,把他抽象成一个类型. 下次遇到和这个字符串同类的字符串,我们只需要判断是否符合特征,就知道这个字符串是不是同类的. 举个例子: 每 ...

  3. C++ STL 标准模板库介绍与入门

    目录 1.概述 1.1.C++ 标准库 1.2.Boost库 2.STL 版本 2.1.HP 原始版本 2.2.P. J. 实现版本 2.3.RW 实现版本 2.4.SGI 实现版本 2.5.STLp ...

  4. Computer:正则表达式技术的简介(元字符/普通字符使用字典及其方法总结大全)、相关库介绍、案例应用之详细攻略

    Computer:正则表达式技术的简介(元字符/普通字符使用字典及其方法总结大全).相关库介绍.案例应用之详细攻略 导读:正则表达式有等价的概念,比较晦涩难懂,其实,使用正则表达式本身就是个难题.当面 ...

  5. 最新超详细C++经典Boost库介绍

    Boost库 Boost库是为C++语言标准库提供扩展的一些C++程序库的总称,由Boost社区组织开发.维护.Boost库可以与C++标准库完美共同工作,并且为其提供扩展功能. 目录 Boost库 ...

  6. Python怎么安装第三方库-numpy-libnum等; (详细版)

    自述 作为一个萌新刚刚整完python,惊奇的发现还需要安装第三方库 -.- ; 于是我在CSDN上找教程谁知都是些***文章, 给了三串代码没有任何说明 - -.(难受),于是我想写个详细版的: 过 ...

  7. OpenGL开发库的详细介绍

    OpenGL开发库的组成 开发基于OpenGL的应用程序,必须先了解OpenGL的库函数.它采用C语言风格,提供大量的函数来进行图形的处理和显示.OpenGL库函数的命名方式非常有规律.所有OpenG ...

  8. 《利用Python进行数据分析·第2版》第13章 Python建模库介绍

    第1章 准备工作 第2章 Python语法基础,IPython和Jupyter 第3章 Python的数据结构.函数和文件 第4章 NumPy基础:数组和矢量计算 第5章 pandas入门 第6章 数 ...

  9. Linux下curses函数库的详细介绍

    Linux下curses函数库的详细介绍 curses库介绍 安装 curses库函数介绍 初始化和重置函数 管理屏幕的函数 输出到屏幕 从屏幕读取 清除屏幕 移动光标 字符属性 管理键盘的函数 键盘 ...

最新文章

  1. 19.使用Matlab计算各种距离
  2. Java 数据类型缓存池
  3. 辞九门回忆用计算机,辞九门回忆(单轨,曲速70,适合UTAU调教;midishow首发)...
  4. Python3字符串拼接
  5. java可存储100个整数的数组_定义一个一维整数数组,其中储存1000个1至100以内的整数,并统计出整数出现的次数(Java写出来)...
  6. 设计高效sql一般经验谈
  7. c++如何输入数组_从一个数组中找出 N 个数,其和为 M 的所有可能最 nice 的解法...
  8. ES6 解构赋值的用法笔记
  9. node.js Websocket消息推送---GoEasy
  10. conda失败说没有写权限_爱情中,为什么男生表白失败,女生还说可以继续做朋友,想过没有...
  11. HTML/CSS class6 table布局
  12. 基于深度学习下的稳定学习究竟是什么?因果学习?迁移学习?之一
  13. 速腾激光雷达 xavier环境驱动配置踩坑记录
  14. 什么是 CSS 预处理器/后处理器?
  15. 如何将一个压缩包在不解压的情况下,进行分卷
  16. WebView 视频播放,全屏按钮显示不出来,全屏后不能播放视频
  17. python概率编程_Python概率编程库PyMC应用案例二则,pymc应用案例
  18. [R语言学习笔记] - R语言及Rstudio配置合集
  19. 虚拟键码如何在c语言里使用方法,二、Windows按键消息—虚拟键码
  20. 钉钉在线课堂回放一键下载

热门文章

  1. string类型与date类型转换
  2. 消息中间| JAVA消息中间件概述
  3. cuda之thread,block,gird详解
  4. php guzzlehttp,使用Guzzle执行HTTP请求
  5. Ubuntu禁用触摸板
  6. [CTS2019]无处安放(提交答案)
  7. 【正点原子Linux连载】第二十五章 语音识别项目 摘自【正点原子】I.MX6U嵌入式Qt开发指南V1.0.2
  8. java特性菜鸟_Java attack - Java 特性
  9. 北理计算机优营会被鸽吗,被放鸽子以后~
  10. 无法直接安装Ubuntu16.04的Win10系统安装教程