为什么C++正则表达式这么慢?
Why is C++ regex so slow?
我是C++新手,必须处理文本文件。我决定用正则表达式来做这件事。我想出的正则表达式:
(([^\s^=]+)\s*=\s*)?"?([^"^\s^;]+)"?\s*;[!?](\w+)\s*
我根据以下帖子编写了C++代码:
C++ 正则表达式使用 regex_search(( 提取所有子字符串
这是C++代码:
#include "pch.h"
#include <iostream>
#include <fstream>
#include <string>
#include <regex>
#include <chrono>
#include <iterator>
void print(std::smatch match)
{
}
int main()
{
std::ifstream file{ "D:\File.txt" };
std::string fileData{};
file.seekg(0, std::ios::end);
fileData.reserve(file.tellg());
file.seekg(0, std::ios::beg);
fileData.assign(std::istreambuf_iterator<char>(file),
std::istreambuf_iterator<char>());
static const std::string pattern{ "(([^\s^=]+)\s*=\s*)?"?
([^"^\s^;]+)"?\s*;[!?](\w+)\s*" };
std::regex reg{ pattern };
std::sregex_iterator iter(fileData.begin(), fileData.end(), reg);
std::sregex_iterator end;
const auto before = std::chrono::high_resolution_clock::now();
std::for_each(iter, end, print);
const auto after = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> delta = after - before;
std::cout << delta.count() << "msn";
file.close();
}
我正在处理的文件包含 541 行。上面的程序需要 5 秒才能获得所有 507 场比赛。我以前在 C# 中做过这样的事情,从来没有这么慢的正则表达式。所以我在 C# 中尝试了同样的事情:
var filedata = File.ReadAllText("D:\File.txt", Encoding.Default);
const string regexPattern =
"(([^\s^=]+)\s*=\s*)?"?([^"^\s^;]+)"?\s*;[!?](\w+)\s*";
var regex = new Regex(regexPattern, RegexOptions.Multiline |
RegexOptions.Compiled );
var matches = regex.Matches(filedata);
foreach (Match match in matches)
{
Console.WriteLine(match.Value);
}
这只需要 500 毫秒即可找到所有 507 个匹配项 + 在控制台上打印。因为我必须与C++一起工作,所以我需要更快。
如何提高C++计划的速度?我做错了什么?
我刚刚遇到了同样的问题,最后我用boost::regex
替换了std::regex
,我想你也可以尝试另一个正则表达式库(boost/google re2...(。
更新: 我正在使用 GCC 5.4。
我提到了 C 风格的字符串,但我并不是说尽可能多地使用纯 C 风格可以提高正则表达式的性能。我的意思很简单,我们应该能够在编译时做更多的事情,在运行时对std::string
做更少的操作,这样我们才能获得更好的性能。
原始答案
如您所知,我们有两种类型的字符串:C 样式字符串和std::string
.
std::string
编码时可以使用,但我们可以说它是一种沉重的东西(这就是为什么有些人不喜欢它(。首先,std::string
使用了堆内存,这意味着它使用了new
或malloc
;其次,std::string
在其大小增加的同时使用了某种特定的算法(将当前大小加倍,并将当前内容移动到新的内存区域并释放旧内容(。这些会导致性能问题。
正则表达式显然是关于字符串的,它需要在任何地方玩字符串。std::regex
玩得很多std::string
,这就是为什么std::regex
的表现不好的原因。
此外,std::string
完全是运行时的东西。例如,可以在编译时初始化 C 样式字符串,但不能在编译时初始化std::string
。这意味着有关std::string
的事情很少能在编译时进行优化。 下面是一个关于我们如何利用编译时在运行时获得非常好的性能的示例: 为什么使用 constexpr 初始化变量是在运行时而不是在编译时计算
的std::regex
在编译时不能做太多事情,因为它使用std::string
,这也可能导致性能问题。这就是为什么人们可能喜欢CTRE(编译时正则表达式(库的原因。
如果std::string_view
可以在std::regex
的源代码中使用,我认为性能会更好。
C++承诺:"不要为你不使用的东西付费。没有冒犯任何人,但我个人认为std::regex
违背了承诺。如果C++标准委员会认为函数比任何其他事情都重要,我会说为什么不使用Java。
- 使用正则表达式regex_search在字符串中查找字符串
- 在 C++ 中使用正则表达式错误时出现问题 括号表达式中的范围无效
- C++正则表达式无限循环
- FindPackageHandleStandardArgs.cmake:137 的 CMake 错误(消息):找不到 Boost (缺少:正则表达式)(找到合适的版本"1.72.0",
- 定义有趣的宏和正则表达式在Z3 C++绑定
- 带有多个字符分隔符的正则表达式
- C++ 使用增强正则表达式库时断言崩溃
- 有人可以帮助我处理正则表达式吗?
- 使用正则表达式获取大括号块的列表
- 正则表达式以匹配数字的重复模式,后跟任何类型的分隔符?
- 组合正则表达式部分使用 | 不起作用的 C++
- 为什么C++正则表达式这么慢?
- 如何使HTML5电子邮件验证正则表达式在C++中工作?
- 在C++中实现正则表达式
- C++正则表达式替换整个单词
- 用C++编写正则表达式的正确方法是什么?
- 如何从Stroustrup的C++书中解释这个正则表达式?
- 为什么这个正则表达式C++在括号表达式中抛出无效范围异常?
- C++:匹配正则表达式,什么是匹配?
- C++:正则表达式匹配代码,打印多个匹配项?