Довольно простая реализация:
sub convert {
my $keyword = shift @_;
my $map = @_ ? $_[ 0 ] : \%MAP;
my @parts = do {
my $regex = do {
my $letters = join('', keys %$map);
qr/([$letters])/i;
};
split($regex, $keyword, -1);
};
my $n_slots = ( -1 + scalar @parts )/2;
my $n_variants = 2 ** $n_slots;
my @variants;
my $i = 0; # use $i = 1 instead to keep the original $keyword
# out of the list of variants
while ( $i < $n_variants ) {
my @template = @parts;
my $j = 1;
my $k = $i;
for ( 1 .. $n_slots ) {
$template[ $j ] = $map->{ lc $parts[ $j ] } if $k & 1;
$j += 2;
$k >>= 1;
}
push @variants, join( '', @template );
$i++;
}
return \@variants;
}
sub main {
my $keyword = shift @_;
my $fh = @_ ? ( open( $_[ 0 ], 'a' ) or die $! ) : \*STDOUT;
print $fh "$_\n" for @{ convert( $keyword ) };
}
main( $ARGV[ 0 ] );
Пример прогона:
% perl 6995383.pl rogerDaViS
rogerDaViS
rogerD@ViS
rogerDaV!S
rogerD@V!S
rogerDaVi$
rogerD@Vi$
rogerDaV!$
rogerD@V!$
Прошу прощения за отсутствие комментариев и отсутствие обработки ошибок (срочно потраченных на время), но основная идея заключается в том, что если существует n слотов, которые можно заменить, и при условии, что для каждого слота существует только одна возможная альтернатива, то есть 2 ^ n вариантов (включая оригинальное ключевое слово). Биты (двоичное представление) индекса $i
используются для отслеживания того, какие позиции заменять на каждой итерации внешнего цикла. Следовательно, итерация с $i == 0
оставляет ключевое слово без изменений. (Поэтому, если вам не нужен этот «вариант», просто shift
из его возвращенного массива.)
Это всего лишь первая трещина в этом. В дополнение к комментариям и обработке ошибок, я уверен, что если немного подумать, эту реализацию можно значительно улучшить / ужесточить.
НТН ...