В 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$1\E*(\Q$1\E\\*)?" : "\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.Однако он возвращает ложное значение для вашего случая №4, потому что, если я действительно что-то упустил, 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 - хотя, очевидно, это будет немногобольше работы.