如何确定正则表达式是否与另一个正则表达式正交?

时间:2009-01-28 20:02:49

标签: regex fsm

我想我的问题最好用(简化)示例解释。

正则表达式1:

^\d+_[a-z]+$

正则表达式2:

^\d*$

正则表达式1 永远不会匹配正则表达式2匹配的字符串。 因此,假设正则表达式1是正交到regex 2。

很多人问我正交的意思,我会试着澄清一下:

S1 成为正则表达式1匹配的(无限)字符串集。 S2 是正则表达式2匹配的字符串集。 正则表达式2与正则表达式1正交 iff S1和S2的交点为空。 正则表达式^ \ d_a $将不正交,因为字符串'2_a'位于集合S1 S2中。

如果两个正则表达式彼此正交,如何以编程方式确定?

最好的情况是某些库实现类似的方法:

/**
 * @return True if the regex is orthogonal (i.e. "intersection is empty"), False otherwise or Null if it can't be determined
 */
public Boolean isRegexOrthogonal(Pattern regex1, Pattern regex2);

14 个答案:

答案 0 :(得分:9)

“正交”是指“交叉点是空集”我接受了吗?

我会为交集构造正则表达式,然后转换为普通形式的常规语法,看看它是否为空语言...

然后,我是一个理论家......

答案 1 :(得分:7)

  

我会为交集构造正则表达式,然后转换为普通形式的常规语法,看看它是否为空语言...

这似乎是用大炮射击麻雀。为什么不构建产品自动机并检查接受状态是否可以从初始状态到达?这也会立即在十字路口给你一个字符串,而不必先构建一个正则表达式。

  

我会有点惊讶地发现有一个多项式时间解决方案,我不会惊讶地发现它等同于停止问题。

我只知道一种方法,它涉及从正则表达式创建DFA,这是指数时间(在退化情况下)。它可以简化为暂停问题,因为一切都是,但暂停问题是 可以

  

如果是最后一个,则可以使用任何RE可以转换为有限状态机的事实。如果它们具有相同的节点集,则两个有限状态机是相等的,具有连接这些节点的相同弧。

     

所以,考虑到我认为你正在使用的正交定义,如果你将你的RE翻译成FSM并且那些FSM不相等,那么RE是正交的。

这不正确。您可以在边缘标记的多图形意义上使用两个非同构的DFA(FSM),但接受相同的语言。此外,如果不是这样,您的测试将检查两个正则表达式是否接受非相同,而OP需要非重叠语言(空交集)。


另外,请注意\ 1,\ 2,...,\ 9结构不规则:它不能用连接,union和*(Kleene star)表示。如果你想包括替换,我不知道答案是什么。同样令人感兴趣的是,无上下文语言的相应问题是不可判定的:没有算法需要两个无上下文语法G1和G2,如果L(G1)∩L(g2)≠Ø,则返回true。

答案 2 :(得分:7)

这个问题发布已经过去了两年,但我很高兴地说现在只需在这里调用“genex”程序即可确定:https://github.com/audreyt/regex-genex

$ ./binaries/osx/genex '^\d+_[a-z]+$' '^\d*$'
$

空输出表示没有与两个正则表达式匹配的字符串。如果它们有任何重叠,它将输出整个重叠列表:

$ runghc Main.hs '\d' '[123abc]' 
1.00000000      "2"
1.00000000      "3"
1.00000000      "1"

希望这有帮助!

答案 3 :(得分:2)

首先让我说我不知道​​如何构建这样的算法,也不知道任何实现它的库。但是,我不会惊讶地发现,对于任意复杂性的一般正则表达式都存在这种情况。

每个正则表达式都定义了表达式可以生成的所有字符串的常规语言,或者如果您愿意,还可以定义正则表达式“匹配”的所有字符串。将语言视为一组字符串。在大多数情况下,该集合将无限大。您的问题询问正则表达式给出的两个集合的交叉点是否为空。

至少在第一次逼近时,我无法想象一种在不计算集合的情况下回答这个问题的方法,对于无限集合而言,这将花费比你更长的时间。我认为可能有一种方法来计算一个有限的集合,并确定何时一个模式被详细说明超出了另一个正则表达式所要求的范围,但这并不是直截了当的。

例如,只需考虑简单表达式(ab)*(aba)*b。什么是决定从第一个表达式生成abab然后停止而不检查ababababababab等因为它们永远不会工作的算法?您不能只是生成字符串并检查,直到找到匹配项,因为当语言不相交时,它永远不会完成。我无法想象在一般情况下会有什么作用,但在这种情况下,有些人比我好得多。

总而言之,这是一个难题。我会有点惊讶地发现有一个多项式时间解决方案,而且我不会惊讶地发现它等同于停止问题。虽然正则表达式不是图灵完整的,但似乎至少可能存在解决方案。

答案 4 :(得分:2)

fsmtools可以在有限状态机上执行各种操作,唯一的问题是将正则表达式的字符串表示形式转换为fsmtools可以使用的格式。对于简单的情况来说,这绝对是可能的,但是在看到{前面,后面}等高级功能的情况下会很棘手。

你可能也看看OpenFst,虽然我从未使用它。但它支持交叉。

答案 5 :(得分:2)

  

优秀点\ 1,\ 2位......这是无关的上下文,因此无法解决。小点:不是一切都可以简化为止...程序对等例如...... - Brian Postow

[我正在回复评论]

IIRC,a^n b^m a^n b^m不是无上下文的,所以(a\*)(b\*)\1\2也不是因为它是相同的。 ISTR { ww | w ∈ L }即使L很“好”也不会“很好”,因为regularcontext-free很好。

我修改了我的陈述:RE 中的所有都可以简化为暂停问题; - )

答案 6 :(得分:1)

您可以使用Regexp::Genex之类的内容生成测试字符串以匹配指定的正则表达式,然后使用第二个正则表达式上的测试字符串来确定2个正则表达式是否正交。

答案 7 :(得分:1)

在某些情况下,证明一个正则表达式与另一个正则表达式正交可能是微不足道的,例如相同位置中的互斥字符组。除了最简单的正则表达式之外,这是一个非常重要的问题。对于严肃的表达方式,对于群体和反向引用,我甚至会说这可能是不可能的。

答案 8 :(得分:1)

我相信kdgregory是正确的,你使用正交来表示Complement

这是正确的吗?

答案 9 :(得分:1)

我会做以下事情:

  • 使用类似以下结构的东西将每个正则表达式转换为FSA:

    struct FSANode
    {
        bool accept;
        Map<char, FSANode> links;
    }
    List<FSANode> nodes;
    FSANode start;
    

请注意,这并非易事,但对于简单的正则表达式来说应该不那么困难。

  • 制作一个新的组合节点,如:

    class CombinedNode
    {
        CombinedNode(FSANode left, FSANode right)
        {
            this.left = left;
            this.right = right;
        }
    
        Map<char, CombinedNode> links;
        bool valid { get { return !left.accept || !right.accept; } }
    
        public FSANode left;
        public FSANode right;
    }
    

根据左侧和右侧的相同字符构建链接,您将获得两个创建新CombinedNode的FSANode。

然后从CombinedNode(leftStart,rightStart)开始,找到生成集,如果有任何无效的CombinedNodes,则该集不是“正交”。

答案 10 :(得分:1)

将每个正则表达式转换为DFA。从一个DFA的接受状态创建epsilon过渡到第二个DFA的开始状态。实际上,您将通过添加epsilon过渡来创建NFA。然后将NFA转换为DFA。如果开始状态不是接受状态,并且接受状态是可达的,则两个正则表达式不是“正交的”。 (因为它们的交集是非空的。)

已知有将正则表达式转换为DFA以及将NFA转换为DFA的过程。你可以看一下Sipser的“计算理论导论”这本书的程序,或者只是在网上搜索。毫无疑问,许多本科生和毕业生必须为一个“理论”课或其他课程做这件事。

答案 11 :(得分:1)

我终于找到了我正在寻找的图书馆:

dk.brics.automaton

用法:

/**
 * @return true if the two regexes will never both match a given string
 */
public boolean isRegexOrthogonal( String regex1, String regex2 ) {
   Automaton automaton1 = new RegExp(regex1).toAutomaton();
   Automaton automaton2 = new RegExp(regex2).toAutomaton();
   return automaton1.intersection(automaton2).isEmpty();
}

应该注意的是,实现不支持并且不能支持复杂的RegEx功能,例如后引用。请参阅介绍"A Faster Java Regex Package"的博文dk.brics.automaton

答案 12 :(得分:0)

这似乎是对orthogonal这个词的不同用法,而不是我以前的用法。

如果两个RE以任何方式重叠,您认为它们是正交的吗?或者如果一个是另一个的子集?或者只是如果它们不能用于匹配相同的文本?

如果是最后一个,则可以使用任何RE可以转换为有限状态机的事实。如果它们具有相同的节点集,则两个有限状态机是相等的,具有连接这些节点的相同弧。

所以,考虑到我认为你正在使用的正交定义,如果你将你的RE翻译成FSM并且那些FSM不相等,那么RE是正交的。

答案 13 :(得分:0)

我说得太早了。我在原始帖子中所说的内容无法解决,但如果您可以将正则表达式转换为DFA格式,那么您可以尝试执行的操作。

你可以在我第一篇文章中提到的书中找到这个程序:“计算理论导论”第2版由Sipser提供。它位于第46页,脚注中有详细信息。

该过程将为您提供一个新的DFA,它是两个DFA的交集。如果新DFA具有可达到的接受状态,则交集非空。