C 如何快速在多个正则表达式键上进行字符串匹配?

C 如何快速在多个正则表达式键上进行字符串匹配?,c,regex,algorithm,search,C,Regex,Algorithm,Search,我有一个元素数组,其键是正则表达式。 我想提出一个快速算法,给定一个字符串(不是正则表达式)将在不到O(N)的时间内返回基于执行键正则表达式的匹配数组值 目前,我对数组进行线性扫描,对于每个元素,我使用posix regexec API执行相应的正则表达式,但这意味着要找到匹配的元素,我必须在整个数组中进行搜索 我知道如果aray只由简单的字符串作为键组成,我可以保留它的排序器并使用bsearch风格的API,但是使用regex看起来并不那么容易 我是不是遗漏了什么 下面是一个例子 // thi

我有一个元素数组,其键是正则表达式。 我想提出一个快速算法,给定一个字符串(不是正则表达式)将在不到O(N)的时间内返回基于执行键正则表达式的匹配数组值

目前,我对数组进行线性扫描,对于每个元素,我使用posix regexec API执行相应的正则表达式,但这意味着要找到匹配的元素,我必须在整个数组中进行搜索

我知道如果aray只由简单的字符串作为键组成,我可以保留它的排序器并使用bsearch风格的API,但是使用regex看起来并不那么容易

我是不是遗漏了什么

下面是一个例子

// this is mainly to be considered
// as pseudocode
typedef struct {
  regex_t  r;
  ... some other data
} value;

const char *key = "some/key";
value my_array[1024];
bool  my_matches[1024];
for(int i =0; i < 1024; ++i) {
  if(!regexec(&my_array[i].r, key, 0, 0, REG_EXTENDED))
    my_matches[i] = 1;
  else
    my_matches[i] = 0;
}
//这主要是要考虑的
//作为伪码
类型定义结构{
正则表达式;
…一些其他数据
}价值观;
const char*key=“some/key”;
值my_数组[1024];
bool my_匹配[1024];
对于(int i=0;i<1024;++i){
if(!regexec(&my_数组[i].r,key,0,0,REG_扩展))
我的_匹配[i]=1;
其他的
我的_匹配[i]=0;
}
但是,正如你所看到的,以上是线性的。 谢谢

附录

我把一个简单的可执行文件放在一起,执行上面的算法和下面的答案中提出的一些东西,其中形成一个大型正则表达式,它构建一个二叉树的子正则表达式,并对其进行导航以找到所有匹配项。
源代码在这里(GPLv3):
编译时使用:
g++-O3-o regex\u search./regex\u search.cpp-lrt

并使用:
/regex\u搜索“a/b”
(或使用
--help
标志查看选项)

有趣的是(我会说,正如预期的那样),在树中搜索时,执行正则表达式的数量较少,但每次比较都要复杂得多,因此最终它所花费的时间与向量的线性扫描相平衡。结果打印在
std::cerr
上,因此您可以看到它们是相同的


当使用长字符串和/或多个令牌运行时,请注意内存使用情况;准备好按Ctrl-C键以阻止系统崩溃。

这是可能的,但我认为您需要编写自己的正则表达式库来实现它

因为您使用的是posix正则表达式,所以我假设您打算实际使用正则表达式,而不是现代正则表达式库倾向于实现的计算特性的随机集合。正则表达式在union(以及许多其他操作)下是封闭的,因此可以从正则表达式数组构造单个正则表达式

每个正则表达式都可以由DFA(确定性有限状态自动机)识别,而DFA(无论多么复杂)可以识别(或无法识别)与字符串长度成线性关系的字符串。给定一组DFA,您可以构造一个联合DFA来识别所有DFA的语言,而且(稍微修改DFA接受字符串的含义),您可以恢复有关DFA的哪个子集与字符串匹配的信息

我将尝试使用与DFAs相同的术语。假设我们有一组dfa
M={M1…Mn}
,它们共享一个字母∑。因此,我们:

Mi=(Qi,∑,δi,qi0,Fi),其中Qi={qij}表示0≤ j<| Qi |和Qi&子集;Fi.

我们构造了联合DFA
M&union;=(Q&Union;∑,δ&Union;,Q&Union;0)
(是的,否
F
;我会讲到这一点)如下:

q&Union;0=

δ&并;(,α)=
对于每个
α&in;∑

Q&Union
包括通过
δ&并集可到达的所有状态
q&Union开始;0

我们可以使用标准的闭包算法来计算,时间与
δi
转移函数大小的乘积成正比

现在,为了对字符串α1…αm进行联合匹配,我们以通常的方式运行联合DFA,从它的开始符号开始,依次将其转换函数应用于每个α。一旦我们读取了字符串中的最后一个符号,DFA将处于某种状态。从该状态中,我们可以提取与字符串匹配的
Mi
集:
{Mi | qiji&in;Fi}

为了实现这一点,我们需要单个DFA是完整的(即,每个符号上的每个状态都有一个转换)。某些DFA构造算法生成的DFA在某些符号上缺少转换(表示语言中没有带有该前缀的字符串);此类DFA必须增加一个不可接受的“sink”状态,该状态在每个符号上都有向自身的转换

我不知道有哪一个正则表达式库能够充分地公开其DFA来实现上述算法,但是编写一个简单的正则表达式库并不需要做太多的工作,它不会试图实现任何非常规特性。您还可以找到DFA库

从正则表达式构造DFA在表达式的大小上可能是指数级的,尽管这种情况很少见。(非确定性FA可以在线性时间内构造,但在某些情况下,NFA上的功率集构造将需要指数时间和空间。请参阅Wikipedia文章。)然而,一旦构建DFA,联合FA可以在时间上与DFA大小的乘积成比例地构造

因此,通过将每个正则表达式编译成一个DFA并维护DFA集,应该很容易允许对正则表达式集进行动态修改。当正则表达式集更改时,只需要重新生成union DFA

希望一切都有帮助。

不到O(N)次?假设N=字符串的长度,这似乎是不可能的。我所知道的每个正则表达式实现都是以输入字符串的大小线性运行的(例如:谷歌的RE2)。@de