CTRE编译时正则匹配空Subject字段失败问题求助
问题:CTRE编译时正则匹配空Subject字段失败的解决办法
我使用编译时正则表达式库编写了如下代码:
constexpr auto pattern = ctll::fixed_string{ "\\d+|(?<=FLAGS ).*?\\)|(?<=Subject: ).*?(?=\r\n)|(?<=From: ).*?(?=\r\n)|(?<=To: ).*?(?=\r\n)|(?<=Date: ).*?(?=\r\n)" }; auto all_matches = ctre::search_all<pattern>(header); for (const auto& match : all_matches) { auto num_matches = match.count(); auto m0 = match.get<0>().to_string(); std::cout << m0 << std::endl; }
输入字符串如下:
* 9999 FETCH (UID 1000 RFC822.SIZE 9393939 FLAGS (\Seen) BODY[HEADER.FIELDS (From To Subject Date)] {132}\r\nDate: Tue, 20 Feb 2024 02:28:43 -0800\r\nSubject: \r\nFrom: Eshy <eshy@example.com>\r\nTo: Eshy <eshy@example.com>\r\n\r\n)
当Subject字段内容为空时,CTRE无法跳过该位置继续匹配,但相同正则表达式在regex101中可正常运行,请问有解决方法吗?
解决思路及方案
问题根源是CTRE对零长度匹配的处理逻辑与PCRE(regex101使用的引擎)不同。当(?<=Subject: ).*?(?=\r\n)匹配空内容时,CTRE的匹配指针无法正确推进,导致后续匹配卡住。
1. 调整正则表达式,避免零长度匹配陷阱
修改正则,让每个字段的匹配逻辑更明确,确保匹配后指针能跳过整个字段行:
constexpr auto pattern = ctll::fixed_string{ "\\d+|" "(?<=FLAGS ).*?\\)|" "Subject:\\s*(.*?)(?=\r\n)|" "From:\\s*(.*?)(?=\r\n)|" "To:\\s*(.*?)(?=\r\n)|" "Date:\\s*(.*?)(?=\r\n)" };
这里用Subject:\\s*(.*?)(?=\r\n)替代原有的环视匹配,\\s*会匹配零或多个空白字符(包括空内容的情况),匹配完成后指针会直接跳到\r\n之后,不会停留在原地。
2. 手动控制匹配指针(适用于正则无法修改的场景)
如果不能调整正则,可以放弃search_all,改用循环手动控制匹配起始位置,遇到零长度匹配时强制推进指针:
size_t current_pos = 0; const auto& input = header; while (current_pos < input.size()) { auto match = ctre::search<pattern>(input.substr(current_pos)); if (!match) break; auto m0 = match.get<0>().to_string(); std::cout << m0 << std::endl; // 若匹配长度为0,强制推进1个字符避免死循环 current_pos += match.length() > 0 ? match.length() : 1; }
3. 更新CTRE到最新版本
部分旧版CTRE存在零长度匹配的处理bug,更新到官方最新版本可能直接解决该问题。
内容的提问来源于stack exchange,提问作者Eshy
相关产品推荐
相关产品推荐

