我有一大堆正则表达式,当匹配时调用一个特定的http处理程序。一些较旧的正则表达式是无法访问的(例如a.c* ⊃ abc*
),我想修剪它们。
是否有一个给出两个正则表达式的库会告诉我第二个是否是第一个的子集?
我一开始并不确定这是否具有可判定性(它的气味就像一个不同名称的暂停问题)。但事实证明it's decidable。
答案 0 :(得分:12)
Trying to find the complexity of this problem lead me to this paper.
问题的正式定义可以在以下内容中找到:这通常被称为包含问题
R的包含问题是测试两个给定的表达式r,r'∈R, 是否r⊆r'。
该论文有一些很好的信息(摘要:除了最简单的表达式之外的所有表达都相当复杂),但是搜索包含问题的信息会直接导致StackOverflow。这个答案已经有a paper describing a passable polynomial time algorithm的链接,应该涵盖很多常见案例。
答案 1 :(得分:5)
如果正则表达式使用典型程序匹配器(如Perl,Java,Python,Ruby等中的那些)的“高级功能”,允许接受非常规语言,那么你就不走运了。问题通常是不可判定的。例如。一个下推自动机是否识别相同的无上下文(CF)语言的问题是不可判定的。扩展正则表达式可以描述CF语言。
另一方面,如果正则表达式在理论意义上是“真”,只包括连接,交替和Kleene星在有限字母表的字符串上,加上这些的通常语法糖(字符类,+ ,?等,然后有一个简单的多项式时间算法。
我不能给你图书馆,但是这个:
For each pair of regexes r and s for languages L(r) and L(s)
Find the corresponding Deterministic Finite Automata M(r) and M(s)
Compute the cross-product machine M(r x s) and assign accepting states
so that it computes L(r) - L(s)
Use a DFS or BFS of the the M(r x s) transition table to see if any
accepting state can be reached from the start state
If no, you can eliminate s because L(s) is a subset of L(r).
Reassign accepting states so that M(r x s) computes L(s) - L(r)
Repeat the steps above to see if it's possible to eliminate r
将正则表达式转换为DFA通常使用Thompson的结构来获得非确定性自动机。使用子集构造将其转换为DFA。跨产品机器是另一种标准算法。
这一切都是在1960年代制定的,现在已成为任何优秀的本科计算机科学理论课程的一部分。该主题的黄金标准是Hopcroft and Ullman, Automata Theory。
答案 2 :(得分:4)
数学部分有一个答案:https://math.stackexchange.com/questions/283838/is-one-regular-language-subset-of-another。
基本理念:
如果您只计算新的转换和结果状态,从一开始就省略所有不可达状态,那将是有益的。
答案 3 :(得分:3)
我找到了一个提供set操作的python正则表达式库。
http://github.com/ferno/greenery
证明Sub ⊆ Sup ⇔ Sub ∩ ¬Sup is {}
。我可以用python库实现这个:
import sys
from greenery.lego import parse
subregex = parse(sys.argv[1])
supregex = parse(sys.argv[2])
s = subregex&(supregex.everythingbut())
if s.empty():
print("%s is a subset of %s"%(subregex,supregex))
else:
print("%s is not a subset of %s, it also matches %s"%(subregex,supregex,s)
的示例:
subset.py abcd.* ab.*
abcd.* is a subset of ab.*
subset.py a[bcd]f* a[cde]f*
a[bcd]f* is not a subset of a[cde]f*, it also matches abf*
库可能不健壮,因为正如其他答案中所提到的,您需要使用最小DFA才能使其正常工作。我不确定ferno's图书馆是否(或可以作出)保证。
暂时不说:使用库来计算逆向或简化正则表达式很有趣。
a(b|.).*
简化为a.+
。这是非常小的。
abf*
的倒数是([^a]|a([^b]|bf*[^f])).*|a?
。试着自己想出来吧!