You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用std::regex解析字符串触发栈溢出,是否为标准库缺陷?

问题描述

我尝试用std::regex将字符串拆分为多个子部分,使用的正则表达式如下:

"(^([\s\S]+?)\s*(\W)\s*[\r\n]+A\.\s*((?:.+(?:[\r\n](?![B-D]\.))*)+)[\r\n]+B\.\s*((?:.+(?:[\r\n](?![CD]\.))*)+)[\r\n]+C\.\s*((?:.+(?:[\r\n](?!D\.))*)+)[\r\n]+D\.\s*([\s\S]+)$)"

多数情况下该正则运行正常,但处理特定文本时抛出栈溢出异常:

Unhandled exception:
Unhandled exception at 0x00007FF7C93FCF66 in Convert.exe: 0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x000000FE83A43F98).

异常发生在xtr1common文件的这段代码处:

in the xtr1common:
_EXPORT_STD _NODISCARD constexpr bool is_constant_evaluated() noexcept {
return __builtin_is_constant_evaluated(); }
#endif // _HAS_CXX20

测试使用的字符串:

The portfolio manager from your division thought it might be helpful to the project teams if she delivered a short presentation on the elements in her portfolio. A number of team members, after receiving the e- mail announcement for the presentation, come to you and ask if this meeting is worth their time. After all isn’t a portfolio just a big project? As a Senior Project manager your best response would be:
A.  You’re right. The meeting probably would be a waste of your time
B.  Not really. A portfolio is a group of related projects managed together to achieve synergies between the projects and establish common methods and procedures.
C.  Not really. A portfolio can be a group of programs, projects, or sub-projects designed to help the organization meet specific business goals
 
D.  Not really. A portfolio is a collection of documents, methods, and procedures that help us manage projects

完整测试代码:

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

using std::string;
using std::regex;
using std::smatch;

int main()
{
    string s = R"(The portfolio manager from your division thought it might be helpful to the project teams if she delivered a short presentation on the elements in her portfolio. A number of team members, after receiving the e- mail announcement for the presentation, come to you and ask if this meeting is worth their time. After all isn’t a portfolio just a big project? As a Senior Project manager your best response would be:
A.  You’re right. The meeting probably would be a waste of your time
B.  Not really. A portfolio is a group of related projects managed together to achieve synergies between the projects and establish common methods and procedures.
C.  Not really. A portfolio can be a group of programs, projects, or sub-projects designed to help the organization meet specific business goals
 
D.  Not really. A portfolio is a collection of documents, methods, and procedures that help us manage projects)";
    string pattern = R"(^([\s\S]+?)\s*(\W)\s*[\r\n]+A\.\s*((?:.+(?:[\r\n](?![B-D]\.))*)+)[\r\n]+B\.\s*((?:.+(?:[\r\n](?![CD]\.))*)+)[\r\n]+C\.\s*((?:.+(?:[\r\n](?!D\.))*)+)[\r\n]+D\.\s*([\s\S]+)$)";

    regex questionRegex(pattern, std::regex_constants::ECMAScript /* | std::regex_constants::collate */);
    smatch question_match;
    try {
        if (regex_search(s, question_match, questionRegex)) {
            std::cout << "Query: " << question_match[1] << "\n";
            std::cout << "A: " << question_match[2] << "\n";
            std::cout << "B: " << question_match[3] << "\n";
            std::cout << "C: " << question_match[4] << "\n";
            std::cout << "D: " << question_match[5] << "\n";
        }
    }
    catch (std::regex_error & error)
    {
        std::cout << "error" << error.what();
    }

    return 0;
}

请问这种情况是否意味着std::regex存在缺陷?


问题分析与解决

这不是std::regex的缺陷,问题出在你写的正则表达式上——嵌套量词导致了回溯爆炸,进而触发栈溢出。

看你正则里的这类结构:((?:.+(?:[\r\n](?![B-D]\.))*)+),外层的+和内层非捕获组里的*形成嵌套量词。当正则引擎尝试匹配时,会产生大量回溯分支,持续消耗栈空间,最终导致栈溢出。

另外,原正则还有两处明显问题:

  1. 分组索引对应错误,比如你输出时用question_match[2]对应选项A,但实际[2]是\W的捕获组,会导致输出内容错误;
  2. 匹配换行的逻辑不够兼容,未考虑Windows平台的\r\n格式。

优化后的正则表达式

^([\s\S]+?)\s*(\W)\s*\r?\nA\.\s*((?:(?!\r?\n[B-D]\.).)*)\r?\nB\.\s*((?:(?!\r?\n[CD]\.).)*)\r?\nC\.\s*((?:(?!\r?\nD\.).)*)\r?\nD\.\s*([\s\S]+)$

优化点说明:

  • 把嵌套的(.+(?:...)*)+改成((?:(?!...).)*),用否定前瞻精确控制匹配范围,彻底避免回溯爆炸;
  • 用\r?\n兼容Windows和Unix的换行格式;
  • 简化结构,减少正则引擎的计算负担。

修正后的测试代码

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

using std::string;
using std::regex;
using std::smatch;

int main()
{
    string s = R"(The portfolio manager from your division thought it might be helpful to the project teams if she delivered a short presentation on the elements in her portfolio. A number of team members, after receiving the e- mail announcement for the presentation, come to you and ask if this meeting is worth their time. After all isn’t a portfolio just a big project? As a Senior Project manager your best response would be:
A.  You’re right. The meeting probably would be a waste of your time
B.  Not really. A portfolio is a group of related projects managed together to achieve synergies between the projects and establish common methods and procedures.
C.  Not really. A portfolio can be a group of programs, projects, or sub-projects designed to help the organization meet specific business goals
 
D.  Not really. A portfolio is a collection of documents, methods, and procedures that help us manage projects)";
    // 优化后的正则,修正分组对应关系
    string pattern = R"(^([\s\S]+?)\s*(\W)\s*\r?\nA\.\s*((?:(?!\r?\n[B-D]\.).)*)\r?\nB\.\s*((?:(?!\r?\n[CD]\.).)*)\r?\nC\.\s*((?:(?!\r?\nD\.).)*)\r?\nD\.\s*([\s\S]+)$)";

    regex questionRegex(pattern, std::regex_constants::ECMAScript);
    smatch question_match;
    try {
        if (regex_search(s, question_match, questionRegex)) {
            std::cout << "Query: " << question_match[1] << "\n";
            std::cout << "A: " << question_match[3] << "\n"; // 修正索引,对应A选项的捕获组
            std::cout << "B: " << question_match[4] << "\n";
            std::cout << "C: " << question_match[5] << "\n";
            std::cout << "D: " << question_match[6] << "\n";
        }
    }
    catch (std::regex_error & error)
    {
        std::cout << "error: " << error.what() << "\n";
    }

    return 0;
}

额外说明

只要解决了回溯爆炸的问题,栈溢出就会消失。如果你的编译器支持C++20及以上,可以用std::format简化输出,但核心问题始终是正则表达式的结构设计。

内容的提问来源于stack exchange,提问作者Mike

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 20:35:08