C++使用Google RE2库读取文件块匹配正则无结果的问题排查
问题:Google RE2按块读取文件时无法匹配正则,按行读取存在重复匹配遗漏
我用C++的Google RE2库对文件按块(每次8192字节)做正则匹配,用ifstream::read()读取没问题,但不管文本里有没有匹配内容(已用regex101验证),程序都没输出匹配结果。试过这些方案都无效:
- 使用
re2::StringPiece作为输入 - 使用
char*数组作为输入 - 使用
std::string作为输入 - 尝试
PartialMatch()与FindNConsume()函数
补充:按行读取时能正确检测到匹配,但同一行里同一模式多次匹配只会打印一次;换成按块读取就完全找不到匹配。
两种实现代码
按行读取的实现
void searchPattern(const std::string &filename, const std::string &pattern) { // opening the file to see if it is valid std::ifstream file(filename); if(!file.is_open()) { std::cout << "Filename is invalid and cannot be accessed!" << std::endl; } // creating RE2 object with the pattern RE2 regex(pattern); // checking for the validity of the regex pattern if(!regex.ok()) { std::cout << "Regex pattern invalid, not enforceable." << std::endl; } std::string line; auto lineNumber = 0; // reading every line of the file itself while(std::getline(file, line)) { if(RE2::PartialMatch(line, regex)) { std::cout << "Line " << lineNumber << ": " << line << std::endl; } lineNumber++; } file.close(); }
按块读取的实现
void RegexPattern(const std::string filename, const std::string pattern, int buffer_size) { // opening the file to see if it is valid std::ifstream file(filename); if(!file.is_open()) { std::cout << "Filename is invalid and cannot be accessed!" << std::endl; } // creating RE2 object with the pattern RE2 regex(pattern); re2::StringPiece res; // checking for the validity of the regex pattern if(!regex.ok()) { std::cout << "Regex pattern invalid, not enforceable." << std::endl; } char* buff_string = new char[buffer_size + 1]; buff_string[buffer_size] = '\0'; while(true) { file.read(buff_string, buffer_size); absl::string_view in(buff_string); re2::StringPiece res; if(RE2::PartialMatch(buff_string, regex)) { std::cout << "Match found for regex: " << regex.pattern() << std::endl; std::cout << buff_string << std::endl; } if(file.eof()) break; } file.close(); }
测试文本
Mountain789Sunshine12Mountain789Sunshine12 4321Sunshine12505050 qwerty99 667788 river9 1234 Book987 999999
测试正则模式为Sunshine。
解决方案
核心问题分析
按块读取失效原因:
- 未处理实际读取长度:
read()不一定读满缓冲区,直接用整个缓冲区会带入无效垃圾数据,干扰RE2匹配。 - 未处理跨块匹配:目标字符串可能被切分在两个块之间,单纯按块匹配会遗漏。
PartialMatch()未结合有效数据范围:无效数据导致匹配逻辑异常。
- 未处理实际读取长度:
按行读取重复匹配遗漏原因:
PartialMatch()仅判断是否存在匹配,不会遍历所有匹配项,同一行多次匹配只会触发一次输出。
修复后的按块读取代码
#include <fstream> #include <iostream> #include <string> #include "re2/re2.h" void RegexPattern(const std::string& filename, const std::string& pattern, int buffer_size) { std::ifstream file(filename, std::ios::binary); if (!file.is_open()) { std::cout << "无法打开文件!" << std::endl; return; } RE2 regex(pattern); if (!regex.ok()) { std::cout << "正则模式无效:" << regex.error() << std::endl; return; } // 保存上一块末尾的残留内容,处理跨块匹配 std::string leftover; char* buff = new char[buffer_size]; while (true) { file.read(buff, buffer_size); std::streamsize bytes_read = file.gcount(); if (bytes_read <= 0) break; // 拼接残留内容与当前块有效数据 std::string current_data = leftover + std::string(buff, bytes_read); leftover.clear(); // 循环查找所有匹配项 re2::StringPiece input(current_data); std::string match; while (RE2::FindAndConsume(&input, regex, &match)) { std::cout << "找到匹配:" << match << std::endl; } // 保留当前块末尾可能的不完整匹配前缀,长度为正则最长前缀长度 int max_prefix_len = regex.PrefixLength(); if (input.size() > max_prefix_len) { leftover = input.substr(input.size() - max_prefix_len); } else { leftover = input.ToString(); } } // 处理最后剩余的残留内容 if (!leftover.empty()) { re2::StringPiece input(leftover); std::string match; while (RE2::FindAndConsume(&input, regex, &match)) { std::cout << "找到匹配:" << match << std::endl; } } delete[] buff; file.close(); }
修复后的按行读取代码(支持多次匹配)
#include <fstream> #include <iostream> #include <string> #include "re2/re2.h" void searchPattern(const std::string& filename, const std::string& pattern) { std::ifstream file(filename); if (!file.is_open()) { std::cout << "无法打开文件!" << std::endl; return; } RE2 regex(pattern); if (!regex.ok()) { std::cout << "正则模式无效:" << regex.error() << std::endl; return; } std::string line; int lineNumber = 0; while (std::getline(file, line)) { re2::StringPiece input(line); std::string match; bool line_has_match = false; while (RE2::FindAndConsume(&input, regex, &match)) { if (!line_has_match) { std::cout << "行 " << lineNumber << ": " << line << std::endl; line_has_match = true; } std::cout << " 匹配内容:" << match << std::endl; } lineNumber++; } file.close(); }
关键修复点说明
- 有效数据处理:用
gcount()获取实际读取字节数,确保只处理有效内容,避免垃圾数据干扰。 - 跨块匹配处理:保留上一块末尾的潜在匹配前缀,与当前块拼接后再匹配,不会漏掉跨块的目标字符串。
- 全匹配遍历:用
FindAndConsume()循环遍历所有匹配项,解决同一行/块内多次匹配遗漏的问题。 - 错误信息优化:输出正则错误详情,方便调试;文件打开失败后直接返回,避免无效操作。
内容的提问来源于stack exchange,提问作者Manav Gurnani
相关产品推荐
相关产品推荐

