24. 正则表达式

一、什么是正则表达式

  正则表达式(regular expression)又称 规则表达式,是一种文本模式(pattern)。正则表达式使用一个字符串来描述、匹配具有相同规格的字符串,通常被用来检索、替换那些符合某个模式(规则)的文本。正则表达式的核心功能就是处理文本。正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。

  C++ 标准库从 C++ 11 开始提供了正则表达式(Regular Expressions)的支持,通过 <regex> 头文件来实现。C++ 的正则表达式库提供了一组类和函数,用于处理正则表达式匹配、搜索和替换操作。

  • 正则表达式对象 :使用 std::regex 类定义一个正则表达式对象。

  • 匹配操作

    • std::regex_match() 方法:用于检查一个字符串是否与一个正则表达式匹配。
    • std::regex_search() 方法:用于搜索字符串中与正则表达式匹配的部分。
    • std::regex_replace() 方法:用于替换与正则表达式匹配的文本。
    • std::sregex_iterator 迭代器类:用于遍历字符串中所有与正则表达式匹配的子串。返回一个 std::smatch 对象,后者用于存储匹配结果。
  • 匹配结果 :使用 std::smatch 类来存储匹配结果,它包含匹配的子串和相关信息。

  在 C++ 中,主要有两种方法完成模式匹配:“搜索”(searching),即在字符串任意部分中搜索匹配的模式;而 “匹配”(matching)是指判断一个字符串能否从起始处全部匹配某个模式。搜索通过 regex_search() 函数或方法来实现,而匹配是调用 regex_match() 函数或方法实现。

  regex_match() 函数总是从字符串的起始部分对模式进行全部匹配。如果匹配成功,就返回 true;如果匹配失败,就返回 false。

bool regex_match(const std::string& text, const std::regex& e);
bool regex_match(const std::string& text, std::smatch& match, const std::regex& e);
  • 参数 text 是要进行匹配的输入字符串。
  • 参数 estd::regex对象,代表正则表达式。
  • 参数 matchstd::smatch对象(或与 std::smatch类似的类型),用于存储匹配的结果信息。当使用 std::smatch 时,它会包含整个匹配的信息以及任何分组(括号中的子匹配)。

  regex_search() 的工作方式与 regex_match() 完全一致,不同之处在于 regex_search() 会用它的字符串参数,在任意位置对给定正则表达式模式搜索第一次出现的匹配情况。如果搜索到成功的匹配,就会返回 true;否则,返回 false。

bool regex_search(const std::string& text, const std::regex& e);
bool regex_search(const std::string& text, std::smatch& match, const std::regex& e);
  • 参数 text 是要进行匹配的输入字符串。
  • 参数 estd::regex对象,代表正则表达式。
  • 参数 matchstd::smatch对象(或与 std::smatch类似的类型),用于存储匹配的结果信息。当使用 std::smatch 时,它会包含整个匹配的信息以及任何分组(括号中的子匹配)。

  std::regex_replace() 函数用于替换字符串中与正则表达式匹配的文本。

regex_replace(const std::string& text, const std::regex& e, const std::string& replace_text);
regex_replace(const std::string& text, const std::regex& e, const std::string& replace_text, int flags = 0);
  • 参数 text 是要进行匹配的输入字符串。
  • 参数 estd::regex对象,代表正则表达式。
  • 参数 replace_text 是要替换的字符串。
  • 参数 flags 用于指定额外的选项。

  std::regex_replace 命名空间中定义了许多宏用来指定替换方式。

  • std::regex_constants::format_first_only:只替换第一个匹配项。
  • std::regex_constants::format_all:替换所有匹配项。
  • std::regex_constants::format_no_copy:不创建新字符串,而是直接修改输入字符串。

  std::regex_replace 函数返回一个输出迭代器,指向替换后的字符串的第一个字符。你可以将这个输出迭代器用于输出流,或者将替换后的字符串存储在另一个字符串变量中。

  由此可见,regex_match() 试图从字符串的起始部分开始匹配模式,而 regex_search() 函数不但会搜索模式在字符串中第一次出现的位置,而且严格地对字符串从左到右搜索。

  std::sregex_iterator 类的构造函数有多个重载版本,但通常使用的是以下两个版本:

std::sregex_iterator(const std::string::const_iterator& first, const std::string::const_iterator& last, const std::regex& e);
std::sregex_iterator(const std::string& s, const std::regex& e);
  • 参数 first 指向搜索开始的位置。
  • 参数 last 指向搜索结束的位置。
  • 参数 estd::regex对象,代表正则表达式。
  • 参数 s 是 一个 std::string 对象,用于定义搜索的范围。

  字符串的匹配:

#include <iostream>
#include <regex>using namespace std;int main(void) 
{string text = "小樱同学";string pattern = "小樱";regex expression(pattern);smatch match;if (regex_match(text, match, expression)){cout << "Found a match: " << match.str() << endl;}else{cout << "No match found." << endl;}return 0;
}

  字符串的搜索:

#include <iostream>
#include <regex>using namespace std;int main(void) 
{string text = "小樱同学";string pattern = "同学";regex expression(pattern);smatch match;if (regex_search(text, match, expression)) {cout << "Found a match: " << match.str() << endl;cout << "Match position: " << match.position() << endl;cout << "Match prefix: " << match.prefix() << endl;cout << "Match suffix: " << match.suffix() << endl;} else {cout << "No match found." << endl;}return 0;
}

  字符串的替换:

#include <iostream>
#include <regex>using namespace std;int main(void) 
{string text = "你好啊,小樱同学!从现在开始你就是我的朋友啊。小樱同学,请多多关照。";string pattern = "同学";regex expression(pattern);smatch match;cout << regex_replace(text, expression, "同志") << endl;return 0;
}

二、基础语法

2.1、转义字符

  使用正则表达式去检索某些特殊字符的时候,需要用到转义字符,否则检索不到结果,甚至会报错;在 C++ 中,\ 具有转义的意思,会对紧随其后的字符进行转义,如果我们想使用普通的 \ ,需要在使用一个 \ 对它进行转义。

#include <iostream>
#include <regex>using namespace std;int main(void) 
{string text = "abc$def(123(456))";string pattern = "\\(456";regex expression(pattern);smatch match;if (regex_search(text, match, expression)){cout << "Found a match: " << match.str() << endl;}else{cout << "No match found." << endl;}return 0;
}

  由于在 C++ 字符串字面量中反斜杠是一个转义字符,所以在构建模式串时,你需要使用两个反斜杠来表示一个反斜杠。在这个模式串中,我们使用了两次反斜杠 \\ 来转义左括号 (。这里推荐使用推荐原始字符串字面量,这样可以不需要转义反斜杠。

#include <iostream>
#include <regex>using namespace std;int main(void) 
{string text = "abc$def(123(456))";string pattern = R"(\(456)";regex expression(pattern);smatch match;if (regex_search(text, match, expression)){cout << "Found a match: " << match.str() << endl;}else{cout << "No match found." << endl;}return 0;
}

在 C++ 字符串字面量中,反斜杠本身也是一个转义字符,所以我们需要使用两个反斜杠 \\ 来表示一个真正的反斜杠 \

需要用到转义符号的常见字符如下:. * + ( ) $ / \ ? [ ] ^ { }

2.2、字符匹配符

字符匹配符含义实例解释
[]可接收的字符列表[abc]a、b、c 中的任意 1 个字符
[^]不可接收的字符列表[^abc]除 a、b、c 之外的任意 1 个字符
包括数字和特殊符号
-连字符a-z任意一个小写字母
#include <iostream>
#include <regex>using namespace std;int main(void)
{string text = "abc123def4567AbC";regex expression1("[abc]");regex expression2("[^abc]");regex expression3("[a-z]");smatch match;if (regex_search(text, match, expression1)){cout << "Match found: " << match.str() << endl;}if (regex_search(text, match, expression2)){cout << "Match found: " << match.str() << endl;}if (regex_search(text, match, expression3)){cout << "Match found: " << match.str() << endl;}return 0;
}

2.3、元字符

元字符含义
.匹配单个除换行符以外的任意字符
\d匹配 0~9 任意一个数字
\D匹配单个任意非数字字符
\s匹配任意空白字符
\S匹配任意不是空白符的字符
\w匹配字母或数字或下划线的任意字符
\W匹配任意不是字母、数字、下划线的字符
#include <iostream>
#include <regex>using namespace std;int main(void)
{string text = "abc123def4567AbC";regex expression1(R"(\d\d\d)");regex expression2("\\d\\w");smatch match;// 使用 sregex_iterator 遍历所有匹配的结果for (sregex_iterator it(text.begin(), text.end(), expression1), end; it != end; ++it) {match = *it;cout << "Found match: " << match.str() << " at position: " << match.position() << endl;}cout << endl;for (sregex_iterator it(text.begin(), text.end(), expression2), end; it != end; ++it) {match = *it;cout << "Found match: " << match.str() << " at position: " << match.position() << endl;}return 0;
}

元字符的大写表示不匹配;

2.4、重复限定符

  重复限定符用于指定其前面的字符和组合项连续出现多少次。

重复限定符意义
?0 次 或 1 次
*0 次 或 多次
+1 次 或 多次
{n}正好出现 n 次
{n,}至少出现 n 次
{n,m}出现 n 次 至 m 次
#include <iostream>
#include <regex>using namespace std;int main(void)
{string text = "abc123def4567AbC89d115200a1";regex expression1(R"(\d{3,5})");regex expression2(R"(\d+)");smatch match;// 使用 sregex_iterator 遍历所有匹配的结果for (sregex_iterator it(text.begin(), text.end(), expression1), end; it != end; ++it) {match = *it;cout << "Found match: " << match.str() << " at position: " << match.position() << endl;}cout << endl;for (sregex_iterator it(text.begin(), text.end(), expression2), end; it != end; ++it) {match = *it;cout << "Found match: " << match.str() << " at position: " << match.position() << endl;}return 0;
}

2.5、定位符

  定位符,用来指定要匹配的字符串出现的位置。

定位符含义
^指定起始字符
$指定结束字符
\b匹配目标字符串的边界,
边界指的是字串间有空格,或者目标字符串的结束位置
\B匹配非单词边界
#include <iostream>
#include <regex>using namespace std;int main(void)
{string text = "abc123 def4567abc123abc abc89 d115200 a1abc";regex expression1("^abc");regex expression2("abc$");regex expression3(R"(abc\b)");regex expression4(R"(^ab\B)");smatch match;// 使用 sregex_iterator 遍历所有匹配的结果for (sregex_iterator it(text.begin(), text.end(), expression1), end; it != end; ++it) {match = *it;cout << "Found match: " << match.str() << " at position: " << match.position() << endl;}cout << endl;for (sregex_iterator it(text.begin(), text.end(), expression2), end; it != end; ++it) {match = *it;cout << "Found match: " << match.str() << " at position: " << match.position() << endl;}cout << endl;for (sregex_iterator it(text.begin(), text.end(), expression3), end; it != end; ++it) {match = *it;cout << "Found match: " << match.str() << " at position: " << match.position() << endl;}cout << endl;for (sregex_iterator it(text.begin(), text.end(), expression4), end; it != end; ++it) {match = *it;cout << "Found match: " << match.str() << " at position: " << match.position() << endl;}return 0;
}

2.6、选择匹配符

  正则表达式用符号 | 来表示或,也叫做分支条件,当满足正则表达里的分支条件的任何一种条件时,都会当成匹配成功。

#include <iostream>
#include <regex>using namespace std;int main(void)
{string text = "你好啊,小樱同学,欢迎你加入小樱班,从现在开始你就是我的朋友啊,小樱同志,请多多关照。";regex expression("小樱同学|小樱同志");smatch match;// 使用 sregex_iterator 遍历所有匹配的结果for (sregex_iterator it(text.begin(), text.end(), expression), end; it != end; ++it) {match = *it;cout << "Found match: " << match.str() << " at position: " << match.position() << endl;}return 0;
}

2.6、分组组合

  重复限定符是作用在与它相邻的最左边的一个字符。正则表达式中可以使用小括号 () 来做分组,也就是括号中的内容会作为一个整体。

2.6.1、捕获分组

  我们可以使用 std::smatch 类来获取匹配结果。正则表达式字符串中的第一对括号是第 1 组,第二对括号是第 2 组,依次类推。使用 match[i] 就可以取得匹配文本的不同部分。match[0]返回这个匹配的文本。

捕获分组说明
(pattern)非命名捕获。捕获匹配的子字符串。编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其它捕获结果则根据左括号的顺序从 1 开始自动编号。
#include <iostream>
#include <regex>using namespace std;int main(void)
{string text = "我是小樱,我的身份证明是37028419860401232X";string pattern = R"(\d{6}(\d{4})(\d{2})(\d{2})\d{3}[\dX])";regex expression(pattern);smatch match;// 使用std::sregex_iterator遍历所有匹配项  for (sregex_iterator i = sregex_iterator(text.begin(), text.end(), expression); i != sregex_iterator(); ++i) {  match = *i;  // match[0] 包含整个匹配项  // match[1] 是第一个捕获组// match[2] 是第二个捕获组cout << "整个匹配项: " << match[0] << endl;for (int i = 1; i < match.size(); i++){cout << "第" << i << "个捕获组: " << match[i] << endl;}}  return 0;
}

2.6.2、非捕获分组

非捕获分组说明
(?:pattern)匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储以后使用的匹配。
例如:“小樱(?:同学|同志)” 等价于 “小樱同学|小樱同志”
(?=pattern)它是一个非捕获匹配。
例如:“Harmony(?=2|3)” 匹配 “Harmony2” 中的 “Harmony”,但不匹配 “Harmony1” 中的 “Harmony”
(?!pattern)该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配。
例如:“Harmony(?=2|3)” 匹配 “Harmony1” 中的 “Harmony”,但不匹配 “Harmony2” 中的 “Harmony”
#include <iostream>
#include <regex>using namespace std;int main(void)
{string text = "你好啊,小樱同学,欢迎你加入小樱班,从现在开始你就是我的朋友啊,小樱同志,请多多关照。";regex expression1("小樱(?:同学|同志)");regex expression2("小樱(?=同学|同志)");regex expression3("小樱(?!同学|同志)");smatch match;// 使用std::sregex_iterator遍历所有匹配项  for (sregex_iterator i = sregex_iterator(text.begin(), text.end(), expression1); i != sregex_iterator(); ++i) {  match = *i;  cout << "整个匹配项: " << match[0] << endl;}cout << endl;for (sregex_iterator i = sregex_iterator(text.begin(), text.end(), expression2); i != sregex_iterator(); ++i) {  match = *i;  cout << "整个匹配项: " << match[0] << endl;}cout << endl;for (sregex_iterator i = sregex_iterator(text.begin(), text.end(), expression3); i != sregex_iterator(); ++i) {  match = *i;  cout << "整个匹配项: " << match[0] << endl;}return 0;
}

2.7、非贪婪匹配

  当 ? 元字符紧随任何其它限定符 (*、+、?、{n}、{n,}、{n,m})之后,匹配模式是 “非贪婪匹配”。非贪婪匹配搜索到、尽可能短的字符串。而默认的贪婪匹配搜索到的尽可能长的字符串。

#include <iostream>
#include <regex>using namespace std;int main(void)
{string text = "abc111111abc";// 贪婪匹配regex expression1(R"(\d{3,5})");// 非贪婪匹配regex expression2(R"(\d{3,5}?)");smatch match;// 使用std::sregex_iterator遍历所有匹配项  for (sregex_iterator i = sregex_iterator(text.begin(), text.end(), expression1); i != sregex_iterator(); ++i) {  match = *i;  cout << "整个匹配项: " << match[0].str() << endl;}cout << endl;for (sregex_iterator i = sregex_iterator(text.begin(), text.end(), expression2); i != sregex_iterator(); ++i) {  match = *i;  cout << "整个匹配项: " << match[0].str() << endl;}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/61252.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB绘制克莱因瓶

MATLAB绘制克莱因瓶 clc;close all;clear all;warning off;% clear all rand(seed, 100); randn(seed, 100); format long g;% Parameters u_range linspace(0, 2*pi, 100); v_range linspace(0, pi, 50); [U, V] meshgrid(u_range, v_range);% Parametric equations for t…

2、 家庭网络发展现状

上一篇我们讲了了解家庭网络历史(https://blog.csdn.net/xld_hung/article/details/143639618?spm1001.2014.3001.5502),感兴趣的同学可以看对应的文章&#xff0c;本章我们主要讲家庭网络发展现状。 关于家庭网络发展现状&#xff0c;我们会从国内大户型和小户型的网络说起&…

Vue3 -- 项目配置之eslint【企业级项目配置保姆级教程1】

下面是项目级完整配置1➡eslint&#xff1a;【吐血分享&#xff0c;博主踩过的坑你跳过去&#xff01;&#xff01;跳不过去&#xff1f;太过分了给博主打钱】 浏览器自动打开项目&#xff1a; 你想释放双手吗&#xff1f;你想每天早上打开电脑运行完项目自动在浏览器打开吗&a…

【SQL】E-R模型(实体-联系模型)

目录 一、介绍 1、实体集 定义和性质 属性 E-R图表示 2. 联系集 定义和性质 属性 E-R图表示 一、介绍 实体-联系数据模型&#xff08;E-R数据模型&#xff09;被开发来方便数据库的设计&#xff0c;它是通过允许定义代表数据库全局逻辑结构的企业模式&#xf…

LLM - 计算 多模态大语言模型 的参数量(Qwen2-VL、Llama-3.1) 教程

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/143749468 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 影响 (…

基于Java Springboot成都旅游网

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…

css 使用图片作为元素边框

先看原始图片 再看效果 边框的四个角灭有拉伸变形,但是图片的中部是拉伸的 代码 border-style: solid;/* 设置边框图像的来源 */border-image-source: url(/static/images/mmwz/index/bk_hd3x.png);/* 设置如何切割图像 */border-image-slice: 66;/* 设置边框的宽度 */border…

【阅读记录-章节1】Build a Large Language Model (From Scratch)

目录 1. Understanding large language models1.1 What is an LLM?补充介绍人工智能、机器学习和深度学习的关系机器学习 vs 深度学习传统机器学习 vs 深度学习&#xff08;以垃圾邮件分类为例&#xff09; 1.2 Applications of LLMs1.3 Stages of building and using LLMs1.4…

【WSL+Ubuntu】默认用户被意外变更为 root 后切回原来的默认用户

引言 在使用 Windows Subsystem for Linux (WSL) Ubuntu 时&#xff0c;在 ~ 目录下使用 ls 命令&#xff0c;发现所有文件都消失了&#xff0c;让我误以为文件被清空了。实际上是因为WSL Ubuntu的默认用户被意外地改变为了 root。那么&#xff0c;如何恢复并切回原来的默认用…

模式:每个服务一个数据库

Pattern: Database per service。 背景 如用微服务架构模式开发一个在线商店应用程序。大多数服务需要在某种数据库中持久化数据。如&#xff0c;订单服务存储订单信息&#xff0c;而客户服务存储客户信息。 问题 微服务应用程序中的数据库架构是什么&#xff1f; 驱动力…

Acme PHP - Let‘s Encrypt

Lets Encrypt是一个于2015年三季度推出的数字证书认证机构&#xff0c;旨在以自动化流程消除手动创建和安装证书的复杂流程&#xff0c;并推广使万维网服务器的加密连接无所不在&#xff0c;为安全网站提供免费的SSL/TLS证书。 使用PHP来更新证书&#xff1a; Acme PHP | Rob…

如何实现主备租户的无缝切换 | OceanBase应用实践

对于DBA而言&#xff0c;确保数据库的高可用性、容灾等能力是其日常工作中需要持续思考和关注的重要事项。一方面&#xff0c;可以利用数据库自身所具备的功能来实现这些目标&#xff1b;若数据库本身不提供相应功能&#xff0c;DBA则需寻找其他工具来增强数据库的高可用性和容…

超越GPT-4o-mini | 北大开源「国产o1」大模型,{多阶段自主推理}让小模型也能“放大招“!

01、LLaVA-o1背景简介 以OpenAI o1为代表的大型语言模型展示了强大的推理能力&#xff0c;这充分的验证了语言模型推理时间缩放的有效性。然而&#xff0c;视觉对于使模型能够充分理解世界并扩展其认知能力同等重要。因此&#xff0c;开发一个融合语言和视觉的多模态模型&#…

Unity类银河战士恶魔城学习总结(P126 Item ToolTip物品提示)

【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili 教程源地址&#xff1a;https://www.udemy.com/course/2d-rpg-alexdev/ 本章节实现了把鼠标放到物品上面就会显示物品属性 UI_ItemTooltip.cs 功能实现&#xff1a;该脚本的核心功能是展示和隐藏物品的工具提示…

11.13机器学习_线性回归

十 集成学习方法之随机森林 机器学习中有一种大类叫集成学习&#xff08;Ensemble Learning&#xff09;&#xff0c;集成学习的基本思想就是将多个分类器组合&#xff0c;从而实现一个预测效果更好的集成分类器。集成算法可以说从一方面验证了中国的一句老话&#xff1a;三个…

【机器学习】数学知识:欧式距离(Euclidean Distance)和曼哈顿距离(Manhattan Distance)

欧式距离和曼哈顿距离是两种常用的距离度量方法&#xff0c;用于衡量两点之间的相似性或差异性。它们在几何分析、数据挖掘、机器学习等领域有广泛应用。 1. 欧式距离 概念 欧式距离&#xff08;Euclidean Distance&#xff09;是最常见的直线距离度量方法&#xff0c;源于欧…

hydra基础知识

hydra基础知识 1、yaml的使用 1.1 基础介绍 主要是用来写配置文件 优势: 层级式可以写注释安装: pip install pyyaml1.2 语法 2、omegaconf 2.1 基础介绍 为什么需要omegaconf? omegaconf主要是对python原生的字典,列表类型的增强,通过omegaconf能够更好的处理yaml…

递归(3)----力扣40组合数2,力扣473火柴拼正方形

给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意&#xff1a;解集不能包含重复的组合。 示例 1: 输入: candidates [10,1,2,7,6,1…

RPC-健康检测机制

什么是健康检测&#xff1f; 在真实环境中服务提供方是以一个集群的方式提供服务&#xff0c;这对于服务调用方来说&#xff0c;就是一个接口会有多个服务提供方同时提供服务&#xff0c;调用方在每次发起请求的时候都可以拿到一个可用的连接。 健康检测&#xff0c;能帮助从连…

Android WMS概览

WMS&#xff08;WindowManagerService&#xff09;是 Android 系统的核心服务&#xff0c;负责管理应用和系统的窗口&#xff0c;包括窗口的创建、销毁、布局、层级管理、输入事件分发以及动画显示等。它通过协调 InputManager 和 SurfaceFlinger 实现触摸事件处理和窗口渲染&a…