sub_match

1. 核心概念:它不是“字符串”,它是“书签”

这是理解 sub_match 最重要的一点:

  • 直觉误区:很多人以为 sub_match 里直接存了 "2023" 这样的字符串。

  • 实际情况sub_match 不存储字符串拷贝。它只存储了两个指针(迭代器),分别指向原字符串中匹配开始和结束的位置。

比喻: 如果原字符串是一本很厚的书,sub_match 并不是把某一页撕下来给你,而是夹了两个书签,告诉你:“这一段内容,从第 50 页第 3 行开始,到第 50 页第 8 行结束”。

优点:非常快,不占内存(不需要复制字符串)。 缺点:如果原书(原字符串)被烧了(被销毁了),这两个书签就失效了(悬空指针)。


2. 三大核心成员变量

当拿到一个 sub_match 对象(比如 matches[1])时,你主要使用这三个功能:

A. .str() —— “给我复印件”

这是最常用的方法。因为它只存了指针,如果你想要一个真正的 std::string 来处理,就调用这个。

C++

std::string s = match.str(); // 把指针指向的范围拷贝出来,变成字符串

B. .length() —— “有多长”

告诉你这段匹配的内容有多少个字符。

C. .matched —— “这个组抓到东西了吗?”

这是一个 bool 变量。 在正则表达式中,有些组是可选的(比如用了 ?*)。如果这个组在这次匹配中没出现,.matched 就是 false


3. 代码实战演示

我们用一个“解析日期”的例子来彻底看懂 sub_match 的内部结构。

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

int main() {
    std::string text = "Today is 2023-12-09.";
    
    // 正则:(\d{4}) -> 年, (\d{2}) -> 月, (\d{2}) -> 日
    // 注意:这里有 3 个括号,也就是 3 个 sub_match
    std::regex pattern(R"((\d{4})-(\d{2})-(\d{2}))");
    
    std::smatch results; // 这是一个数组,里面存的全是 sub_match

    if (std::regex_search(text, results, pattern)) {
        
        // results[0] 是特殊的 sub_match,代表“整个匹配到的式子”
        std::cout << "完整匹配: " << results[0].str() << std::endl; // 输出: 2023-12-09
        
        // results[1] 是第 1 个括号 (年) 的 sub_match
        std::sub_match<std::string::const_iterator> year = results[1];
        std::cout << "年份: " << year.str() << std::endl; // 输出: 2023
        
        // results[2] 是第 2 个括号 (月)
        std::cout << "月份长度: " << results[2].length() << std::endl; // 输出: 2

        // 演示 .matched 属性
        // 假设我们要匹配可选的时间部分 (T\d+)? 
        // 如果原句里没有时间,results[4].matched 就为 false
    }
    return 0;
}

4. 这里的“坑” (高手进阶)

因为 sub_match 只是指针(迭代器),所以它的生命周期必须依附于原字符串。

❌ 极度危险的代码(未定义行为):

std::sub_match<...> get_version() {
    std::string temp = "Version 1.0"; // 这是一个局部变量
    std::regex r(R"(Version (\d+))");
    std::smatch m;
    std::regex_search(temp, m, r);
    
    return m[1]; // 错误!!!
    // 函数结束时,temp 字符串被销毁了。
    // 返回的 sub_match 指向了一块已经被回收的内存。
    // 之后如果你调用 .str(),程序可能会崩溃。
}

✅ 正确做法: 如果你要把结果传出去,必须把它转换成 string

std::string get_version() {
    // ... 同上 ...
    return m[1].str(); // 正确:这就创建了一个独立的字符串拷贝
}

总结

  1. sub_match 是匹配结果的一个切片

  2. 它主要包含两个迭代器(开始和结束)和一个 bool 标志(是否匹配)。

  3. 最常用 .str() 把切片转成字符串。

  4. 切记:原字符串销毁后,sub_match 就不能用了。

发表评论