Reputation: 275
I am new to regular expression.
I need to print all combination 8 characters (alphanumeric) which follow the below pattern.
Upvotes: 1
Views: 479
Reputation: 386396
Regular expressions are used to define a syntax. The match and substitute operators check if a string matches a syntax pattern defined using a regex. I am unaware of any tools that use a regex pattern to generate strings.
When you have an arbitrary number of nested loops, you want Algorithm::Loops's NestedLoops
. In your case, there's a fixed number of loops, but there are so many that NestedLoops
comes in useful anyway.
[I'm assuming you're only interested in the letters and numbers in ASCII.]
Naïve (generates all sequences, and filters out the unwanted ones):
use Algorithm::Loops qw( NestedLoops );
my @syms = ('A'..'Z', 'a'..'z', '0'..'9');
my $iter = NestedLoops([ (\@syms) x 8 ]);
while (my @s = $iter->()) {
my $s = join('', @s);
next if $s !~ /^[a-zA-Z][0-9]/;
next if $s =~ /[a-zA-Z]{4}|[0-9]{3}/;
say $s;
}
Mostly naïve (generates all sequences except obviously bad ones, and filters out the unwanted ones):
use Algorithm::Loops qw( NestedLoops );
my @letters = ('A'..'Z', 'a'..'z');
my @digits = ('0'..'9');
my @syms = (@letters, @digits);
my $iter = NestedLoops([
\@letters,
\@digits,
(\@syms) x 6,
]);
while (my @s = $iter->()) {
my $s = join('', @s);
next if $s =~ /[a-zA-Z]{4}|[0-9]{3}/;
say $s;
}
But that still generates a lot of strings that need to be thrown away. The following only generates the string we want. It does that by generating the patterns that will produce desirable strings (LDLLLDLL
, LDLLLDLD
, LDLLLDDL
, LDLLDLLL
, ...), then builds strings from those patterns.
Efficient algorithm (which doesn't mean the implementation is efficient):
use Algorithm::Loops qw( NestedLoops );
my @letters = ('A'..'Z', 'a'..'z');
my @digits = ('0'..'9');
sub make_pat_gen_iter {
my $raw_pat_gen_iter = NestedLoops([
['L'],
['D'],
(['L','D']) x 6,
]);
return sub {
while (1) {
my @pat = $raw_pat_gen_iter->();
return () if !@pat;
my $pat = join('', @pat);
next if $pat =~ /L{4}|D{3}/;
return @pat;
}
};
}
sub make_gen_iter {
my $pat_gen_iter = make_pat_gen_iter();
my @pat;
my $gen_sub_iter;
return sub {
return () if !$pat_gen_iter;
while (1) {
if (!$gen_sub_iter) {
@pat = $pat_gen_iter->();
if (!@pat) {
$pat_gen_iter = undef;
return ();
}
$gen_sub_iter = NestedLoops([
map { $_ eq 'L' ? \@letters : \@digits } @pat
]);
}
my @s = $gen_sub_iter->();
if (!@s) {
$gen_sub_iter = undef;
next;
}
return join('', @s);
}
};
}
my $gen_iter = make_gen_iter();
while (defined( my $s = $gen_iter->() )) {
say $s;
}
For fun, the following is the complete result of the pattern iterator:
LDLLLDLL LDLLLDLD LDLLLDDL LDLLDLLL LDLLDLLD
LDLLDLDL LDLLDLDD LDLLDDLL LDLLDDLD LDLDLLLD
LDLDLLDL LDLDLLDD LDLDLDLL LDLDLDLD LDLDLDDL
LDLDDLLL LDLDDLLD LDLDDLDL LDLDDLDD LDDLLLDL
LDDLLLDD LDDLLDLL LDDLLDLD LDDLLDDL LDDLDLLL
LDDLDLLD LDDLDLDL LDDLDLDD LDDLDDLL LDDLDDLD
Upvotes: 1
Reputation: 96
You can check each pattern. Let's name the string $str. Generate $str from "00000000" to "zzzzzzzz" and use following if clause to pick up strings that match the patterns.
if ($str =~ /^[A-Za-z][0-9]/ // pattern 1 and 2
&& $str !~ /[0-9]{3}/ // pattern 3
&& $str !~ /[A-Za-z]{4}/) // pattern 4
Upvotes: 0