正则表达式:确定两个正则表达式是否可以匹配相同的输入?

时间:2010-08-04 22:10:32

标签: regex

我想知道两个已知正则表达式之间是否存在冲突,以便允许用户构建互斥正则表达式列表。

例如,我们知道下面的正则表达式完全不同,但它们都匹配xy50

'^xy1\d'
'[^\d]\d2$'

是否可以使用计算机算法确定两个正则表达式是否可能存在此类冲突?怎么样?

5 个答案:

答案 0 :(得分:35)

这里没有停顿问题。您所需要的只是计算^xy1\d[^\d]\d2$的交集是否为非空。

我不能在这里给你一个算法,但这里有两个关于生成交集的方法的讨论,而不是求助于构造DFA:

然后是RAGEL

也可以计算正则表达式的交集。

更新:我刚用OP的正则表达式尝试了Ragel。 Ragel可以从生成的状态机生成graphviz的“点”文件,这非常棒。 OP的正则表达式的交集在Ragel语法中如下所示:

('xy1' digit any*) & (any* ^digit digit '2') 

并具有以下状态机:

enter image description here

空路口:

('xy1' digit any*) & ('q' any* ^digit digit '2')

看起来像这样:

enter image description here

因此,如果所有其他方法都失败,那么您仍然可以通过比较生成的“点”文件来让Ragel计算交集并检查它是否输出空状态机。

答案 1 :(得分:19)

这个问题可以重申为“两种或两种以上的常规语言 表达式有一个非空的交集“?

如果您将问题限制在正则表达式中(没有后向引用,前瞻, lookbehind,或其他允许识别无上下文或更复杂的功能 语言),问题至少是可判定的。常规语言将被关闭 交集,并且有一个算法,它采用两个正则表达式 作为输入并在有限时间内产生识别交叉点的DFA。

每个正则表达式都可以转换为非确定性有限自动机, 然后是确定性有限自动机。可以转换一对DFA 到识别交叉点的DFA。如果有一条路径 开始状态到最终DFA的任何接受状态,交叉点非空 (“冲突”,使用您的术语)。

不幸的是,转换初始NFA时可能会出现指数性爆炸 对于DFA来说,问题在实践中很快就变得不可行了 输入表达式增长。

如果允许对纯正则表达式进行扩展,则所有投注均已关闭 - 这些语言不再在交叉点下关闭,因此这种结构不会 工作

答案 2 :(得分:1)

是的,我认为这是可以解决的:您可以将它们视为生成字符串,而不是将正则表达式视为匹配字符串。也就是说,他们将匹配的所有字符串。

令[R]为正则表达式R生成的字符串集。然后,给定正则表达式R和T,我们可以尝试将T与[R]匹配。如果[R]中有一个与T匹配的字符串,则[R]匹配T

应该可以将其开发成算法,其中[R]根据需要延迟构造:正常的正则表达式匹配将尝试匹配输入字符串中的下一个字符,然后前进到字符串中的下一个字符,修改后的算法将检查对应于输入正则表达式的FSM是否可以在其当前状态下生成匹配字符,然后同时前进到“所有下一个状态”。

答案 3 :(得分:0)

另一种方法是利用Dan Kogai的Perl Regexp::Optimizer代替。

ugTopActivity.ChartDataClicked += new ChartDataEventHandler((sender , e) =>
   ugTopActivity_ChartDataClicked(sender,e,new FillSceneGraphEventArgs()));

..首先,优化然后丢弃所有冗余模式。

也许Ron Savage的Regexp::Assemble可能会更有帮助。 它允许将任意数量的正则表达式组合成单个正则表达式,该表达式匹配单个RE匹配的所有内容。*或两者的组合。

*但是,您需要了解Perl和Java或其他PCRE风格之间的一些差异。

答案 4 :(得分:0)

如果要在Java中查找库,则可以使用'&'运算符来使用自动机:

RegExp re = new RegExp("(ABC_123.*56.txt)&(ABC_12.*456.*\\.txt)", RegExp.INTERSECTION); // Parse RegExp
    Automaton a = re.toAutomaton(); // convert RegExp to automaton

    if(a.isEmpty()) { // Test if intersection is empty
      System.out.println("Intersection is empty!");
    }
    else {
      // Print the shortest accepted string
      System.out.println("Intersection is non-empty, example: " + a.getShortestExample(true));
    }

原始答案:

Detecting if two regexes could possibly match the same string