没有简单的方法。
只要您的正则表达式仅使用标准功能(我认为 Perl 允许您在匹配中嵌入任意代码),您就可以从每个表达式生成一个 nondeterministic finite-state automaton (NFA),它紧凑地编码 RE 匹配的所有字符串。
给定任意一对 NFA,可以判断它们的交集是否为空。如果交集不为空,则某些字符串匹配对中的两个 RE(反之亦然)。
标准的可判定性证明是先将它们确定为DFAs,然后构造一个新的 DFA,其状态是两个 DFA 的状态对,其最终状态恰好是这对中的两个状态最终在他们原来的 DFA 中。或者,如果您已经展示了如何计算 NFA 的补码,那么您可以(德摩根定律风格)通过 complement(union(complement(A),complement(B))) 获得交集。
不幸的是,NFA->DFA 涉及潜在的指数级爆炸(因为 DFA 中的状态是 NFA 中状态的子集)。来自Wikipedia:
一些常规语言类可以
只能用确定性来描述
大小增长的有限自动机
的大小呈指数级增长
最短等效正则
表达式。标准示例是
这里的语言 L_k 由
字母表 {a,b} 上的所有字符串
其倒数第 k 个字母等于 a。
顺便说一句,你绝对应该使用OpenFST。您可以将自动机创建为文本文件并尝试最小化、交叉等操作,以了解它们对您的问题的效率。已经存在开源 regexp->nfa->dfa 编译器(我记得一个 Perl 模块);修改一个以输出 OpenFST 自动机文件并播放。
幸运的是,可以避免状态子集爆炸,并使用与 DFA 相同的构造直接与两个 NFA 相交:
如果A ->a B(在一个NFA中,你可以从状态A到B输出字母'a')
和X ->a Y(在另一个 NFA 中)
然后在路口(A,X) ->a (B,Y)
(C,Z) 是最终的,如果 C 在一个 NFA 中是最终的并且 Z 在另一个 NFA 中是最终的。
要启动该过程,您需要从两个 NFA 的启动状态对开始,例如(A,X) - 这是交叉口 NFA 的开始状态。每次您第一次访问一个状态时,根据上述规则为离开这两个状态的每对弧生成一个弧,然后访问这些弧到达的所有(新)状态。您将存储扩展状态弧的事实(例如,在哈希表中)并最终探索从一开始就可以到达的所有状态。
如果您允许 epsilon 转换(不输出字母),那很好:
如果A ->epsilon B 在第一个 NFA 中,那么对于您到达的每个状态 (A,Y),添加弧 (A,Y) ->epsilon (B,Y) 并且对于第二位置 NFA 中的 epsilons 类似。
在将正则表达式转换为 NFA 时,Epsilon 转换在合并两个 NFA 时很有用(但不是必需的);每当您有交替 regexp1|regexp2|regexp3 时,您就采用联合:一个 NFA,其起始状态具有到每个 NFA 的 epsilon 转换,代表交替中的正则表达式。
判断 NFA 是否为空很容易:如果您从开始状态进行深度优先搜索时达到了最终状态,那么它就不是空的。
这种 NFA 交点类似于有限状态转换器组合(转换器是输出符号对的 NFA,它们成对连接以匹配输入和输出字符串,或将给定的输入转换为输出)。