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

Regex 正则表达式:确定两个正则表达式是否可以匹配相同的输入?,regex,Regex,我想知道两个已知的正则表达式之间是否存在冲突,以便允许用户构建一个互斥正则表达式列表 例如,我们知道下面的正则表达式非常不同,但它们都匹配xy50: '^xy1\d' '[^\d]\d2$' 是否有可能使用计算机算法来确定两个正则表达式是否存在这种冲突?如何解决?这个问题可以重新表述为:“两种或两种以上语言描述的语言是否规则?” 表达式有一个非空的交集“ 如果您将问题局限于纯正则表达式(无反向引用,向前看, 查找,或其他允许识别上下文无关或更复杂的功能 语言),这个问题至少是可以确定的。常规语

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

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

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

是否有可能使用计算机算法来确定两个正则表达式是否存在这种冲突?如何解决?

这个问题可以重新表述为:“两种或两种以上语言描述的语言是否规则?” 表达式有一个非空的交集“

如果您将问题局限于纯正则表达式(无反向引用,向前看, 查找,或其他允许识别上下文无关或更复杂的功能 语言),这个问题至少是可以确定的。常规语言在以下情况下关闭: 有一个算法,它采用两个正则表达式 作为输入并在有限时间内生成识别交叉点的DFA

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

不幸的是,在转换初始NFA时,可能会出现指数放大 对于DFA来说,随着数据量的增加,这个问题很快在实践中变得不可行 输入表达式将增长

如果允许对纯正则表达式进行扩展,那么所有的赌注都没有了-- 这样的语言在交叉点下不再是封闭的,所以这种构造不会
工作。

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

这里我不能给你一个算法,但是这里有两个关于生成交叉点的方法的讨论,而不需要构建DFA:

还有拉格尔

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

更新:我刚刚用OP的regexp试用了Ragel。Ragel可以从生成的状态机为graphviz生成一个“点”文件,这太棒了。OP的regexp的交叉点在Ragel语法中如下所示:

('xy1' digit any*) & (any* ^digit digit '2') 
并具有以下状态机:

而空交叉口:

('xy1' digit any*) & ('q' any* ^digit digit '2')
看起来像这样:


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

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

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


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

另一种方法是利用Dan Kogai的Perl

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

也许罗恩·萨维奇的更有用。 它允许将任意数量的正则表达式组合成单个正则表达式,该正则表达式匹配单个REs匹配的所有对象。*或两者的组合


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

如果您正在寻找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));
    }
原始答复:


我暗自怀疑,这个问题等同于停顿问题。@Seamus Campbell:很好!这就是问题的症结所在吗?如果没有,那么如何实施呢?另一种思考方式是。。为什么不添加到用户的正则表达式中,从而使正则表达式相互排斥?也就是说,它与前一个不同,这有帮助吗?我强烈怀疑这是否等同于停顿问题。停止问题适用于图灵机,它们位于乔姆斯基层次结构()的顶部。正则表达式位于层次结构的底部。我怀疑这是一个可以解决的问题,尽管我不知道它是什么,也不知道如何解决。呃,您提供的两个正则表达式都不匹配
xy50
…添加这个有点晚,但一个简单的证明是这样的:在您添加第二个正则表达式与第一个正则表达式的交叉补码之后,您可以通过尝试字母表中的所有字母组合来测试它是否为非空,这些字母组合最多包含与FSM中状态相同数量的字符。剩下的只是抽运引理,因为FSM中的状态数是抽运极限的一个简单上界,我不太明白。但是,它们将匹配的字符串列表可能是无限的。。。此外,尝试将T与[R]匹配是这里的关键点。你的算法需要更好地定义imho。
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));
    }