POSIX文件名匹配(fnmatch)是否有一种已知的O(nm)时间/O(1)空间算法?

POSIX文件名匹配(fnmatch)是否有一种已知的O(nm)时间/O(1)空间算法?,c,regex,string,pattern-matching,substring,C,Regex,String,Pattern Matching,Substring,编辑:哇!我承认,我在fnmatch模式语法中搞砸了?的定义,似乎提出了(可能已经解决)一个更难的问题,它的行为类似于正则表达式中的?。当然,它实际上应该像正则表达式中的一样工作(只匹配一个字符,而不是零或一个)。这反过来意味着我最初的问题简化工作足以解决(现在相当无聊的)原始问题。解决更难的问题仍然很有趣;我可能会在某个时候写出来 从好的方面来看,这意味着像2way/SMOA针头分解这样的分解更有可能适用于这些模式,从而产生比最初期望的性能更好的O(n),甚至O(n/m) 在问题标题中,让m

编辑:哇!我承认,我在
fnmatch
模式语法中搞砸了
的定义,似乎提出了(可能已经解决)一个更难的问题,它的行为类似于正则表达式中的
。当然,它实际上应该像正则表达式中的
一样工作(只匹配一个字符,而不是零或一个)。这反过来意味着我最初的问题简化工作足以解决(现在相当无聊的)原始问题。解决更难的问题仍然很有趣;我可能会在某个时候写出来

从好的方面来看,这意味着像2way/SMOA针头分解这样的分解更有可能适用于这些模式,从而产生比最初期望的性能更好的
O(n)
,甚至
O(n/m)


在问题标题中,让
m
为图案/针的长度,
n
为与其匹配的字符串的长度

我对这个问题很感兴趣,因为我所看到/使用的所有算法都有病态的性能差和可能的堆栈溢出漏洞(由于回溯),或者需要动态内存分配(例如,对于DFA方法或只是避免在调用堆栈上进行回溯)因此,如果程序正在使用
fnmatch
授予/拒绝某种访问权限,则也可能出现危险的故障情况

我愿意相信正则表达式匹配不存在这样的算法,但文件名模式语言比正则表达式简单得多。我已经将问题简化到可以假设模式不使用
*
字符的程度,在这个修改后的问题中,您不是匹配整个字符串,而是搜索字符串中模式的匹配项(如子字符串匹配问题)。如果进一步简化该语言并删除
字符,则该语言只是由固定字符串和括号表达式串联而成,这可以很容易地在
O(mn)
时间和O(1)空间中进行匹配,这可能可以改进为
O(n)
如果在2way和SMOA子字符串搜索中使用的针分解技术可以扩展到这样的括号模式。然而,很自然地,每个
都需要使用或不使用
消耗字符的试验,引入
2^q
的时间因子,其中
q
是模式中
字符的数量

有人知道这个问题是否已经解决了,或者有解决它的想法吗

注意:在定义O(1)空间时,我使用了


注2:本网站详细介绍了我引用的2way和SMOA算法:

您可以创建两个字符串的散列,然后比较它们。哈希计算将在O(m)中进行,而搜索将在O(m+n)中进行

您可以使用类似的方法来计算字符串的散列,其中s[i]是一个字符
正如您所说,这是用于文件名匹配的,您不能在字符串中包含通配符的情况下使用它。祝你好运

你看过谷歌的Russ Cox的
re2
正则表达式引擎了吗

它是一个基于确定性有限自动机的正则表达式匹配引擎,不同于使用回溯模拟非确定性有限自动机的常用实现(Perl、PCRE)。具体设计目标之一是消除您提到的灾难性回溯行为

它不允许在搜索模式中使用一些Perl扩展,如反向引用,但在全局匹配中不需要这样做

我不确定它是否能保证
O(mn)
时间和
O(1)
内存限制,但它已经足够好了,可以在谷歌代码搜索服务存在时运行它


至少它应该是冷静的,看看里面,看看它是如何工作的。Russ Cox已经写了三篇关于re2的文章,而且是开源的。

我觉得这是不可能的


虽然我不能提供一个防弹的论据,但我的直觉是,您将始终能够构造包含q=Theta(m)
字符的模式,在某种意义上,算法需要考虑所有2^q的可能性。这将需要O(q)=O(m)空间来跟踪您当前正在考虑的可能性。例如,NFA算法使用这个空间来跟踪它当前所处的一组状态;蛮力回溯法使用空间作为堆栈(更糟糕的是,除了空间的O(q)外,它还使用O(2^q)时间)。

编辑:哇!我承认,我在
fnmatch
模式语法中搞错了
的定义,似乎解决了一个更难的问题,它的行为类似于正则表达式中的
。当然,它实际上应该像正则表达式中的
一样工作(只匹配一个字符,而不是零或一个)。这反过来意味着我最初的问题简化工作足以解决(现在相当无聊的)原始问题。解决更难的问题仍然很有趣;我可能会在某个时候写出来

下面是更难问题的可能解决方案


我已经在
O(log q)
空间(其中
q
是模式中问号的数量,因此
q
m
)中找到了一个似乎是解决方案的方法,它不确定,但似乎比指数时间更好

首先,快速解释问题的减少。首先在每个
*
处打破模式;它分解为(可能为零长度)
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]