正则表达式以任意顺序匹配另一个字符串中的字符
考虑以下字符串wizard。我想以任何顺序查找它是否在另一个字符串中。
我尝试了以下
while(<>){if($_=~/(?:([wizard])(?!.*1)){6}/i){print"0"}else{print"1"}}
对于输入
Garry Kasparov
Bobby Fischer
Vladimir Kramnik
Wayne Drimaz
Lionel Messi
La Signora
它打印了,111111但肯定是111011.
所以,我尝试了这个(对于相同的输入)
while(<>){if($_=~/(?=[wizard]{6})(?!.*(.).*1).*/i){print"0"}else{print"1"}}
它再次打印111111。在输入编号 4 中,我们可以制作,WaDriaz但只a需要一个。无论如何,我们可以wizard通过重新排列和在任何情况下拼写。为什么它不起作用?
我的代码有什么问题?
回答
这是一个纯正则表达式:对每个字符进行正向预测
use warnings;
use strict;
use feature 'say';
use List::Util qw(uniq); # before v. 1.45 in List::MoreUtils
my $string = shift // q(wizard);
my $patt = join '', map { qq{(?=.*Q$_E)} } uniq split //, $string;
# say $patt;
#--> (?=.*w)(?=.*i)(?=.*z)(?=.*a)(?=.*r)(?=.*d) (for wizard)
while (<DATA>) {
say "Found '$string' in: $_" if /^$patt/is;
}
__DATA__
Garry Kasparov
Bobby Fischer
Vladimir Kramnik
Wayne Drimaz
Lionel Messi
La Signora
全部在一个正则表达式中,具有锚定前瞻且没有开销,这应该非常快。
该Q...E在那里的情况下,搜索字符串包含正则表达式敏感的字符。
请注意,此代码查找具有重复字符 ( latte, rare, letter) 的单词以适合没有 ( later)的单词。在评论中澄清说这确实是想要的行为:重复的字符只需要在目标中找到一次(letter匹配later等)。
回答
以下应该很快(特别是如果您内联 subs):
use feature qw( fc say );
sub make_key {
my %counts;
++$counts{$_} for split //, fc($_[0]) =~ s/PL//rg;
return %counts;
}
sub search {
my ($substr, $str) = @_;
$str = make_key($str);
no warnings qw( uninitialized );
return !( grep { $str->{$_} < $substr->{$_} } keys(%$substr) );
}
my $substr = make_key("wizard");
while (<>) {
chomp;
say search($substr, $_) ? 0 : 1;
}
与几乎所有以前的解决方案不同,这个解决方案不考虑latte在late.
以下是基于正则表达式的解决方案(有一些准备)。这也应该很快(特别是如果你内联 subs)。
use feature qw( fc say );
sub make_re {
my $pat = join ".*?", map quotemeta, sort split //, fc($_[0]) =~ s/PL//rg;
return qr/$pat/s;
}
sub search {
my ($substr, $str) = @_;
return ( join "", sort split //, $str ) =~ $substr;
}
my $substr = make_re("wizard"); # qr/a.*?d.*?i.*?r.*?w.*?z/is
while (<>) {
chomp;
say search($substr, $_) ? 0 : 1;
}
最后,一个纯粹基于正则表达式的解决方案。
use feature qw( fc say );
sub make_re {
my %counts;
++$counts{$_} for split //, fc($_[0]) =~ s/PL//rg;
my $pat =
join "",
map { "(?=".( ( ".*?" . quotemeta($_) ) x $counts{$_} ).")" }
#sort
keys(%counts);
return qr/^$pat/s;
}
my $re = make_re("wizard"); # qr/^(?=.*?a)(?=.*?d)(?=.*?i)(?=.*?r)(?=.*?w)(?=.*?z)/is
while (<>) {
say /$re/ ? 0 : 1;
}
与几乎所有以前的解决方案不同,我的解决方案都没有考虑latte在late.