[项目前置]C++正则表达式

正则表达式介绍

正则表达式(Regular Expression,简称Regex)是一种强大的文本处理工具,它允许你以灵活和高效的方式搜索、替换、检验文本。在C++中,正则表达式的支持是通过标准库中的<regex>头文件提供的,该库自C++11起成为标准的一部分。

正则表达式使用一系列符号和字符来描述或匹配文本模式。这些模式可以简单到单个字符,也可以复杂到描述复杂的字符串模式。

C++标准库提供了多种与正则表达式相关的类和函数,位于<regex>头文件中,包括:

  • std::regex:编译后的正则表达式对象。
  • std::regex_match:检查给定的字符串是否完全匹配正则表达式。
  • std::regex_search:在给定的字符串中搜索正则表达式的匹配。
  • std::regex_replace:使用正则表达式匹配模式来替换字符串。

常用符号和术语

  • 字面量:匹配特定字符的自身。
  • .(点):匹配任何单个字符,除了换行符。
  • []:字符集,匹配方括号内的任意字符。
  • ^ :行的开始,[^]中的^表示非。
  • $:行的结束。
  • *:前面的元素零次或多次出现。
  • +:前面的元素一次或多次出现。
  • ?:前面的元素零次或一次出现。
  • {n}:前面的元素恰好出现n次。
  • {n,}:前面的元素至少出现n次。
  • {n,m}:前面的元素至少出现n次,但不超过m次。
  • |:或,匹配左边或右边的表达式。
  • () :分组,将几个项当作一个单元进行处理,通常与|结合使用。

正则表达式的使用其实很简单,只需要为字符串创造一个匹配规则对象regex,并设置合适的规则。

举例1

cpp 复制代码
#include <iostream>
#include <regex>

int main() {
    std::string text = "Hello World 123";
    std::regex pattern("World");

    // 检查模式是否匹配
    if (std::regex_search(text, pattern)) {
        std::cout << "Found a match!" << std::endl;
    } else {
        std::cout << "No match found." << std::endl;
    }

    return 0;
}

这个示例将输出"Found a match!",因为字符串"Hello World 123"中确实包含"World"。

举例2

验证电子邮箱地址

cpp 复制代码
#include <iostream>
#include <regex>

int main() {
    std::string email = "example@example.com";
    std::regex pattern(R"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})");

    if (std::regex_match(email, pattern)) {
        std::cout << "The email address is valid." << std::endl;
    } else {
        std::cout << "The email address is not valid." << std::endl;
    }

    return 0;
}

在C++中,R"(...)"是一种原始字符串字面量(Raw String Literal)的表示方法,它允许你包含任何字符序列作为字符串的一部分,包括反斜杠 \、双引号 " 和换行符等,而不需要进行转义。

这个规则对于正则表达式的特殊字符(如*, +, ?, |, (, ), [, ], {, }, ^, $, 和.等)不适用,因为这些特殊字符在正则表达式中有特定的含义,

  1. [a-zA-Z0-9._%+-]+:这部分是电子邮件地址的用户名部分,表示电子邮箱可以包含:

    • 小写字母 (a-z)
    • 大写字母 (A-Z)
    • 数字 (0-9)
    • 下划线 (_)
    • 点 (.)
    • 百分号 (%)
    • 加号 (+)
    • 减号 (-)

    + 表示前面的字符集 [a-zA-Z0-9._%+-] 可以出现一次或多次。

  2. @:这是电子邮件地址中必须出现的"@"字符,用于分隔用户名和域名部分。

  3. [a-zA-Z0-9.-]+:这是域名部分,表示电子邮箱可以包含:

    • 小写字母 (a-z)
    • 大写字母 (A-Z)
    • 数字 (0-9)
    • 点 (.)
    • 减号 (-)

    与用户名部分类似,+ 表示这个字符集可以出现一次或多次。

  4. \. :表示点字符(.)。在正则表达式中,点(.)通常表示任何单一字符,因此需要用反斜线(\)进行转义,使其表示字面上的点字符。这个点在电子邮件地址中用于分隔域名和顶级域名(TLD)。

  5. [a-zA-Z]{2,} :这是顶级域名(TLD)部分,可以包含小写字母 (a-z) 和大写字母 (A-Z)。{2,} 表示这部分至少有两个字符,没有上限。这反映了顶级域名通常至少有两个字母,如 .com.org.net 等。

举例3

替换文本

使用正则表达式替换文本中的特定单词或字符。这个例子将文本中的所有"is"替换为"is not"。

cpp 复制代码
#include <iostream>
#include <regex>
#include <string>

int main() {
    std::string text = "This is a test. This test is simple.";
    std::string replaceWith = "is not";
    std::regex pattern(R"(\bis\b)");

    std::string result = std::regex_replace(text, pattern, replaceWith);

    std::cout << result << std::endl;

    return 0;
}
  1. \b :这是一个正则表达式的边界匹配符,它用于匹配一个词的边界。词的边界是指不被字母、数字或下划线(\w)字符包围的位置。这包括字符串的开头和结尾,以及空格或标点符号和字母数字之间的位置。使用\b可以确保你匹配的是独立的单词,而不是包含在其他单词中的子字符串。

  2. is:这部分表示要直接匹配的字符串"is"。

  3. \b:再次使用,确保"is"后面也是一个单词边界。

因此,整个表达式R"(\bis\b)"用于匹配作为独立单词存在的"is",而不会匹配像"this"或"island"这样包含"is"作为子字符串的单词。

举例4

验证字符串是否符合特定的电话号码格式。这里考虑的格式是匹配符合特定格式的中国大陆电话号码。例如+86-123-4567-8910

cpp 复制代码
#include <iostream>
#include <regex>

int main() {
    std::string phone = "+1-123-456-7890";
    std::regex pattern(R"(\+86-\d{3}-\d{4}-\d{4})");

    if (std::regex_match(phone, pattern)) {
        std::cout << "The phone number is valid." << std::endl;
    } else {
        std::cout << "The phone number is not valid." << std::endl;
    }

    return 0;
}
  1. \+ :这里的加号(+)是一个特殊字符,在正则表达式中用于表示前面的元素可以出现一次或多次。但当你想要匹配字面上的加号字符时,需要使用反斜杠对其进行转义,所以\+表示匹配字面上的"+"字符。

  2. 86:这部分直接匹配数字"86",代表中国大陆的国家代码。

  3. -:匹配字面上的连字符或破折号。

  4. \d{3}\d是一个特殊的字符类,匹配任意数字(0-9)。大括号{3}指定了前面的\d(数字)必须恰好出现3次。因此,\d{3}匹配一个由3个数字组成的序列。

  5. -:再次匹配字面上的连字符。

  6. \d{4} :这里\d{4}意味着必须有一个由4个数字组成的序列。和前面一样,\d表示数字,{4}指定了数字必须恰好出现4次。

  7. -:匹配字面上的连字符。

  8. \d{4} :和前面的\d{4}一样,这也是一个由4个数字组成的序列。

举例5

解析http响应

HTTP响应由状态行、响应头部、空行和响应体组成。我们的目标是从HTTP响应文本中提取状态码、响应头部以及响应体。

示例HTTP响应文本

css 复制代码
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 138

<html>
<head>
<title>An Example Page</title>
</head>
<body>
Hello World, this is a very simple HTML document.
</body>
</html>

我们将编写一个C++程序来解析上述HTTP响应,提取出状态码、Content-TypeContent-Length头部以及响应体。

cpp 复制代码
#include <iostream>
#include <regex>
#include <string>

int main() {
    // 示例HTTP响应文本
    std::string httpResponse = R"(HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 138

<html>
<head>
<title>An Example Page</title>
</head>
<body>
Hello World, this is a very simple HTML document.
</body>
</html>)";

    // 正则表达式匹配状态码、Content-Type、Content-Length和响应体
    std::regex statusLinePattern(R"(HTTP\/\d\.\d\s(\d{3}))");
    //(\d{3})括号表示要取出的内容
    // \s表示代表任何空白字符(空格、制表符、换行符....)
    std::regex contentTypePattern(R"(Content-Type:\s(.+))");
    std::regex contentLengthPattern(R"(Content-Length:\s(\d+))");
    std::regex bodyPattern(R"(\r\n\r\n([\s\S]*))"); 
    // [\s\S]* 匹配包括换行符在内的任意字符

    std::smatch matches;

    // 匹配状态码
    if (std::regex_search(httpResponse, matches, statusLinePattern)) {
        std::cout << "Status Code: " << matches[1] << std::endl;
    }

    // 匹配Content-Type
    if (std::regex_search(httpResponse, matches, contentTypePattern)) {
        std::cout << "Content-Type: " << matches[1] << std::endl;
    }

    // 匹配Content-Length
    if (std::regex_search(httpResponse, matches, contentLengthPattern)) {
        std::cout << "Content-Length: " << matches[1] << std::endl;
    }

    // 匹配响应体
    if (std::regex_search(httpResponse, matches, bodyPattern)) {
        std::cout << "Body:\n" << matches[1] << std::endl;
    }

    return 0;
}

std::smatch

在C++中,std::smatchstd::match_results模板类的一个特化版本,专门用于处理字符串(std::string)的搜索和匹配操作。当你使用正则表达式进行搜索或匹配时,std::smatch对象用于存储匹配结果。每个匹配结果包括完整的匹配以及任何括号内的子匹配(即捕获组)。

  • matches[0]包含了正则表达式完整匹配的文本。
  • matches[1]matches[2]、... 包含了正则表达式中第一个、第二个等括号内的子表达式(捕获组)匹配的文本。这些子匹配允许你访问正则表达式中由圆括号()定义的各个部分的匹配结果。
相关推荐
BeanInJ3 小时前
JAVA字符串与正则表达式
java·正则表达式
林深的林4 小时前
正则表达式(2)匹配规则
正则表达式
叶域9 小时前
正则表达式(复习)
大数据·python·正则表达式
运维小贺2 天前
Nginx常用的模块
运维·nginx·正则表达式
Viooocc3 天前
正则表达式
正则表达式
vvilkim3 天前
开发中常用的正则表达式规则与应用
正则表达式
林深的林5 天前
正则表达式(1)
正则表达式
ThisIsClark5 天前
【玩转正则表达式】正则表达式常用语法汇总
正则表达式
ThisIsClark5 天前
【玩转正则表达式】替换与正则表达式的结合
正则表达式