检查一个正则表达式是否涵盖另一个正则表达式
Check if one regex covers another regex
我正在尝试实现文本聚类算法。该算法通过将类似的原始文本行替换为正则表达式来对它们进行聚类,并聚合与每个正则表达式匹配的模式数量,以便提供输入文本的整洁摘要,而不是显示输入文本中的重复模式。在这次尝试中,我遇到了需要查找一个正则表达式是否覆盖另一个正则表达式。
假设我们只关心带有"*"和"+"通配符的正则表达式,即"*"表示字母表的零次或多次出现,而"+"表示字母表的出现一次或多次。还假定字符集为 ASCII。
例如:
1. AB covers AB
This is straightforward.
2. ABC* covers ABC
Because ABC* can generate: ABC, ABCC, ABCCC etc.
3. A*B+C* covers AB+C*
Because A*B+C* can generate ABBC, AABBC, AABBCC etc. which covers
all strings generated by AB+C*.
4. A+M+BC* covers AMM+B+C+M+BC*
Similar to case [3] above.
基本上,我正在寻找以下方法的有效实现,该方法告诉strA(可能包含正则表达式(是否覆盖strB(可能包含正则表达式(。请注意,还应该有一种方法可以转义输入字符串 strA 和 strB 中的正则表达式字符 '*' 和 '+'。
C++方法签名:
bool isParentRegex(const string& strA, const string& strB)
我的想法是,实现需要递归方法,它可能有点复杂。但是我很想知道我是否可以重用现有的实现而不是重新发明轮子,或者是否有任何其他直接的方法可以做到这一点。
考虑到您提出的简单正则表达式语法,解决方案相当微不足道。
以更复杂的例子为例,A+M+BC* covers AMM+B+C+M+BC*
您可以将其重写为A{1,}M{1,}B{1,1}C{0,}
封面A{1,1}M{2,}B{1,}C{1,}M{1,}B{1,1}C{0,}
这导致我们得出一个简单的规则:R1
涵盖R2
如果所有符号都以相同的顺序出现,则所有R1
的下限都小于或等于R2
的下限,并且R1
的上限大于或等于R2
的上限。
现在,简单的规则有一个小问题。 AB*C
涵盖了AC
,即可选符号有可能出现在R1
而不是R2
中。您可以通过在 R2
中插入一个{0,0}
来解决这个问题,当 R1 中有一个(可选(符号没有出现在 R2
中的等效位置时。例如 AB*C
确实涵盖了AB{0,0}C
。
"可选符号"规则是一种优化。如果R1
中的符号不是可选的,R1
肯定不会涵盖R2
。例如 AB+C
不包括AC
.因此,无需插入B{0,0}
。但是如果你这样做,你会发现A{1,1}B{1,}C{1,1}
没有涵盖A{1,1}B{0,0}C{1,1}
,因为B
(1( 的R1
下限大于B
(0( 的R2
下限
我会做一些事情,比如实现一个函数,用于从给定的正则表达式中查找最小的 DFA。让我们假设
DFA GetMinimalDFA(Regex r1(就是这样做的。
bool isParentRegex(Regex r1, Regex r2) {
DFA a = GetMinimalDFA(r1);
DFA b = GetMinimalDFA(Regex.OR(r1,r2))
return a.Equals(b);
}
在Perl中,这将非常简单。第一步是通过将A+
更改为AA*
,A*A
更改为AA*
,并将A*A*
更改为A*
来规范化每个正则表达式:
sub normalize_regex($)
{
local $_ = shift;
s/(.)+/$1$1*/g;
1 while s/(.)*1(?!*)/$1$1*/g or s/(.*)1/$1/g;
return $_;
}
第二步是将第一个正则表达式从与字符串本身匹配的正则表达式转换为与这些字符串匹配的规范化正则表达式的 Perl-正则表达式;例如,AA*B
将转换为 ^AA**?B$
,意思是"字符串开头,后跟 A,后跟零个或多个 A,可选后跟星号,后跟 B, 后跟字符串结尾":
sub regex_to_metaregex($)
{
local $_ = shift;
s/(.)(*?)/$2 ? "Q$1E*(Q$1E\*)?" : "Q$1"/eg;
return qr/^$_$/;
}
第三步不需要解释:
sub does_regex1_cover_regex2($$)
{
my ($r1, $r2) = @_;
$r1 = regex_to_metaregex normalize_regex $r1;
$r2 = normalize_regex $r2;
return scalar $r2 =~ m/$r1/;
}
这将为您的案例 #1–3 返回一个 true 值。但是,它为您的案例 #4 返回一个 false 值,因为除非我真的错过了什么,否则A+M+BC*
不会涵盖AMM+B+C+M+BC*
?
请注意,还应该有一种方法可以转义输入字符串 strA 和 strB 中的正则表达式字符 '*' 和 '+'。
在上面的代码中,我并不担心这一点,但是由于您只担心ASCII,因此预处理步骤可以通过将它们转换为ASCII范围之外的单个字符来处理*
含义*
,+
含义+
和\
含义:
sub process_escapes($)
{
local $_ = shift;
s/\\/x80/g;
s/\+/x81/g;
s/\*/x82/g;
s/x80/\/g;
return $_;
}
(尽管这显然相当黑客(。
在C++中,你可以使用相同的方法——有一些库可以实现 Perl 正则表达式的所有必要功能——尽管显然这需要更多的工作。
请检查这个perl模块源代码,但请记住它不适用于所有正则表达式(因为它将导致解决停止问题。
- 使用正则表达式regex_search在字符串中查找字符串
- 在 C++ 中使用正则表达式错误时出现问题 括号表达式中的范围无效
- C++正则表达式无限循环
- FindPackageHandleStandardArgs.cmake:137 的 CMake 错误(消息):找不到 Boost (缺少:正则表达式)(找到合适的版本"1.72.0",
- 定义有趣的宏和正则表达式在Z3 C++绑定
- 带有多个字符分隔符的正则表达式
- 标准库中的任何正则表达式语法是否支持 (?(定义)用于子模式参考?
- 正则表达式匹配是否保证始终只关注最后一个模式?C++
- 是否可以在正则表达式中命名子图案,然后通过C 中的子图案名称提取匹配
- 正则表达式是否足以分析大型文本
- 是否可以构造与 3 个或更多非连续 UTF 代码点匹配的 PCRE UTF-8 正则表达式
- C++11 正则表达式是否适用于 UTF-8 字符串
- 检查输入字符串是否为数字且为C++,如果是,则将其转换为 int(正则表达式?
- 检查一个正则表达式是否涵盖另一个正则表达式
- 如何确定是否捕获了正则表达式的可选部分
- 元正则表达式:测试正则表达式是否只是一个字符串(没有正则表达式"wildcards")
- 如何查找给定的字符串是否符合十六进制表示法,例如不带正则表达式的0x34FF
- 检查字符串是否可能与正则表达式匹配
- 是否有任何C/ c++编辑器支持替换正则表达式?
- 在c++中使用正则表达式匹配来确定是否为二进制