我的用户给出了一个正则表达式,其中包含默认为贪婪的量词。他可以给任何有效的正则表达式。因此,解决方案将不得不处理用户可以扔给我的任何东西。
如何转换正则表达式,使任何贪婪的量词都是非贪婪的?
Perl是否有一个(?...:regexp)
构造,它将量词的贪婪默认值强制为非贪婪默认值?
如果不是:有没有其他方法可以将带有贪婪量词的正则表达式强制转换为非贪婪的正则表达式?
例如,用户可以输入:
.*
[.*]
[.*]{4,10}
[.*{4,10}]{4,10}
虽然这四个例子看起来可能相似,但它们的含义却完全不同。
如果您只是在每个*
/}
之后添加?
,您将更改最后三个示例中的字符集。
相反,它们应该改为/表现为:
.*?
[.*]
[.*]{4,10}?
[.*{4,10}]{4,10}?
但是,如果匹配的字符串是最小匹配,而不是第一个匹配,Perl将默认为:
$a="aab";
$a=~/(a.*?b)$/;
# Matches aab, not ab
print $1;
但给定非贪婪正则表达式,最小匹配可能可以通过预写.*
:来获得
$a="aab";
$a=~/.*(a.*?b)$/;
# Matches ab
print $1;
"贪婪;不是整个正则表达式的属性。这是一个量词的性质。
它可以为每个量词单独控制。只需在量词后面添加一个?
,使其不贪婪,例如
[a-z]*?
a{2,3}?
[0-9]??
s+?
不,没有任何内置的方法可以将整个正则表达式转换为一些";默认非贪婪";模式您需要解析正则表达式,检测所有量词并相应地更改它们。也许CPAN上有一个正则表达式解析库。
到目前为止,我发现的最接近的是Regexp::Parser模块。我没有尝试,但看起来它可以解析正则表达式,遍历树,进行适当的更改,然后构建一个修改后的正则表达式。请看一看。
您可以使用状态机:
#!/usr/bin/perl
use strict;
use warnings;
my @regexes = ( ".*", "[.*]", "[.*]{4,10}", "[.*{4,10}]{4,10}" );
for (@regexes) {
print "give: $_n";
my $ungreedy = make_ungreedy($_,0);
print "got: $ungreedyn";
print "============================================n"
}
sub make_ungreedy {
my $regex = shift;
my $class_state = 0;
my $escape_state = 0;
my $found = 0;
my $ungreedy = "";
for (split (//, $regex)) {
if ($found) {
$ungreedy .= "?" unless (/?/);
$found = 0;
}
$ungreedy .= $_;
$escape_state = 0, next if ($escape_state);
$escape_state = 1, next if (/\/);
$class_state = 1, next if (/[/);
if ($class_state) {
$class_state = 0 if (/]/);
next;
}
$found = 1 if (/[*}+]/);
}
$ungreedy .= '?' if $found;
return $ungreedy;
}