为什么Regex(c++)需要指数时间
Why is Regex (c++) taking exponential time?
我正在做一些教科书中的正则表达式问题,其中包括以下内容:
"[匹配]以整数开头、以单词结尾的所有字符串。">
我为此写了以下正则表达式:
^[0-9]+s.*+b[a-zA-Z]+$
然而,当我用以下代码在C++中实现这一点时:
#include <iostream>
#include <string>
#include <regex>
#include <time.h>
int main(){
clock_t t;
bool match;
std::string exp = "^[0-9]+\s.*+b[a-zA-Z]+$";
std::string str = "1 a few words 1";
std::string s (str);
std::smatch m;
std::regex e (exp);
while (true){
t = clock();
match = std::regex_match(s, m, e);
s = s + "1";
std::cout << clock() - t << std::endl;
}
}
每次迭代花费的cpu时间为:
1 1181529
2 3398674
3 10102763
4 30370932
5 92491242
看起来它的复杂性是O( 3^n )
为什么会这样?这个表达是不是我做错了什么?
如果我使用像"1 a 1"这样的字符串,尽管常数较小,但增长因子是相同的。
编辑:我看到的问题是我有一个.*+
oops!不过,我不确定为什么这会导致指数行为。
问题在于使用.*+b
,而不是我很确定您想要的.*\b
。
至于为什么这会导致可怕的行为:问题是.*
可以计算任意数量的字符,而+
意味着匹配任意数量的这些字符。但是,为了符合POSIX规范,它必须尝试使整个模式匹配尽可能长的字符串。我的猜测是,要做到这一点,首先要尝试使用.*
来匹配一个字符,并重复它N次。然后,它尝试使用.*
匹配两个字符,并重复该操作M次。然后尝试使用.*
匹配三个字符,并将它们重复L次(依此类推(。哦,请注意,它也不必让所有的.*
模式都匹配相同数量的字符,所以组合的数量呈指数级增长。
由于它不知道总共应该匹配多少个字符,所以它会尝试所有可能的组合,直到到达最后一个,发现它们都匹配相同长度的字符串,并宣布这是一个整体失败(因为您有一个b
,它是一个空白字符,不存在于输入字符串中(。根据你是使用NFA还是DFA进行正则表达式匹配,你可能会得到你观察到的可怕行为,也可能会得到完全线性的行为——或者(取决于你如何进行DFA/NFA转换(它可能只是无法编译正则表达式(这可能不太符合,但仍然可能是更好的行为(。
我认为正则表达式引擎只想找到任何.*一次,因为+。这已经是没完没了的了,所以发动机过了一段时间就取消了操作。
- C++为构建时间获取QDateTime的可靠方法
- 从持续时间构造std::chrono::system_clock::time_point
- 向量 <int> a {N, 0} 和 int arr a[N] = {0} 的时间复杂度有什么区别
- while循环中while循环的时间复杂度是多少
- 使用简单类型列表实现的指数编译时间.为什么
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- 在已经使用Git的情况下减少编译时间
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 如何将包含epoch时间的十六进制字符串转换为time_t
- 从文本文件中读取时钟时间和事件时间并进行处理
- 具有未知值时的时间复杂性
- 如何减少花费的时间
- C++在变量给定的指定时间内关闭电脑
- rcpp函数中的清理时间很长
- C++:floor unix时间戳到UTC月份
- 如何在c++中录制具有精确帧时间戳的视频
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- 比较向量中的元素时所花费的时间呈指数级增长
- 为什么Regex(c++)需要指数时间
- 该递归代码用于计算指数的运行时间是多少