C++11引入了 <regex> 标准库,为开发人员提供了强大的正则表达式支持。正则表达式(RegEx)可用于字符串匹配、搜索、替换等操作,是处理文本数据的利器。本文将从基础语法到高级用法,逐步介绍C++正则表达式如何高效使用。


一、基础准备

1. 引入库和命名空间

在使用正则表达式之前,需包含头文件并使用相关命名空间:

#include <regex>
#include <string>
#include <iostream>

using namespace std;

2. 构建正则表达式

使用 std::regex 对象存储正则表达式:

regex re("\\d+");  // 匹配数字,注意转义字符

二、正则表达式语法基础

1. 常见元字符

元字符含义
.匹配任意单个字符(除换行符)
*匹配前一个字符 0 次或多次
+匹配前一个字符 1 次或多次
?匹配前一个字符 0 次或 1 次
^匹配字符串开头
$匹配字符串结尾
[]匹配括号内的任意一个字符(如 [abc])
\d匹配数字 [0-9]
\D匹配非数字 [^0-9]
\w匹配字母、数字、下划线 [A-Za-z0-9_]

2. 分组和捕获(Groups)

regex re("(\\d{4})-(\\d{2})-(\\d{2})"); // 解析日期格式 YYYY-MM-DD
smatch result;
if(regex_search("2023-04-01", result, re)) {
    cout << "年份: " << result[1] << endl; // 输出 "2023"
    cout << "月份: " << result[2] << endl; // 输出 "04"
}

三、核心函数与用法

1. 检查匹配(regex_match

检查整个字符串是否匹配:

if(regex_match("123abc", regex("\\d+"))) {
    cout << "整个字符串全为数字!"; // 不触发
} else {
    cout << "不匹配"; // 触发
}

搜索字符串中的任意位置匹配:

string s = "苹果30元,香蕉20元";
smatch res;
while(regex_search(s, res, regex("\\d+"))) {
    cout << "价格: " << res[0] << endl; // 输出 "30" 和 "20" 
    s = res.suffix().str(); // 处理剩余部分
}

3. 替换字符串(regex_replace

替换所有匹配项:

string s = "Hello World!";
string replaced = regex_replace(s, regex("World"), "C++");
cout << replaced; // 输出 "Hello C++!"

4. 分割字符串

使用起始迭代器 sregex_token_iterator

string s = "apple,banana,cherry";
regex re(",");
vector<string> parts{
    sregex_token_iterator(s.begin(), s.end(), re, -1),
    sregex_token_iterator()
};
// 输出: parts = {"apple", "banana", "cherry"}

四、正则表达式的修饰符(Flags)

通过修改构造函数参数控制匹配行为:

regex re("\\w+", regex_constants::icase); // 忽略大小写
修饰符说明
std::regex::icase忽略大小写匹配
std::regex::ECMAScript采用 ECMAScript 兼容模式(默认)
std::regex::extended启用扩展语法(允许分隔符)

五、高级技巧

1. 动态构建正则表达式

string pattern = "error" + "(\\d+)"; 
regex re(pattern); 

2. 懒惰匹配与贪婪模式

使用 *?+? 实现懒惰匹配:

regex re("<(.*?)>"); // 匹配最小长度的标签内容

3. 多行模式

启用多行匹配:

regex re("^end$", regex::extended | regex::icase | regex:: multiline);

六、常见问题与解决方案

  1. 中文字符匹配
    使用 [\u4e00-\u9fa5] 表示中文范围:

    regex re("^[\\u4e00-\\u9fa5]+$"); // 匹配纯中文字符串
    
  2. 转义字符问题
    C++字符串需要转义反斜杠,例如 \\d 表示 \d

    regex("^[A-Za-z]+:\\/\\/"); // 匹配 URL 协议头如 http://
    
  3. 性能优化
    对于频繁使用的正则表达式,建议提前编译:

    regex re("\\d+"); // 第一次调用时编译
    

七、实战案例

案例1:邮箱地址验证

bool checkEmail(const string &email) {
    regex re(R"(^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$)");
    return regex_match(email, re);
}

案例2:提取 URL 路径

string extractPath(const string &url) {
    regex re("https?://[^/]+(/[^?]*)", regex::ECMAScript);
    smatch res;
    if(regex_search(url, res, re)) {
        return res[1]; // 返回如 "/path/to/resource"
    }
    return "";
}

八、注意事项

  1. 避免过度复杂化
    复杂的正则表达式可能影响可读性和性能,建议拆分为小规则。

  2. 兼容性检查
    确保编译器支持 C++11 及以上(如 GCC 需要 std=c++11 标志)。

  3. 性能影响
    正则表达式在极端情况下(如超长字符串或回溯爆炸)可能导致显著延迟。


九、参考文献


通过灵活运用 C++正则表达式库,可以极大简化文本处理工作。希望本文示例能帮助你快速上手并解决实际问题!如果需要更复杂的模式匹配,建议逐步拆解需求并结合在线测试工具调试表达式。