正则表达式以任意顺序匹配另一个字符串中的字符

考虑以下字符串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;
}

与几乎所有以前的解决方案不同,这个解决方案不考虑lattelate.


以下是基于正则表达式的解决方案(有一些准备)。这也应该很快(特别是如果你内联 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;
}

与几乎所有以前的解决方案不同,我的解决方案都没有考虑lattelate.


以上是正则表达式以任意顺序匹配另一个字符串中的字符的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>