recursive bruteforce ASCII range

B

bernd

#!/usr/bin/perl -w
#
# hy group
#
# i feel really stupid. could it be that hard?
#
# i try to write a script to bruteforce the ASCII range. something
# like:
#
# a..z
# aa..zz
# aaa..zzz
# ...
#
# but there must be a smarter, solution than writing the same stuff
# over and over again. i'd tried some recursive stuff but failed.
#
# any help really appreciated!
#
# greez bernd (who just didn't see the solution)

use strict;

# one character
foreach my $a ('a'..'z','0'..'9') {
print "$a\n";
}

# two character
foreach my $a ('a'..'z','0'..'9') {
foreach my $b ('a'..'z','0'..'9') {
print "$a$b\n";
}
}

# tree character
foreach my $a ('a'..'z','0'..'9') {
foreach my $b ('a'..'z','0'..'9') {
foreach my $c ('a'..'z','0'..'9') {
print "$a$b$c\n";
}
}
}

# n character ???
 
T

Tassilo v. Parseval

Also sprach bernd:
#!/usr/bin/perl -w
#
# hy group
#
# i feel really stupid. could it be that hard?
#
# i try to write a script to bruteforce the ASCII range. something
# like:
#
# a..z
# aa..zz
# aaa..zzz
# ...
#
# but there must be a smarter, solution than writing the same stuff
# over and over again. i'd tried some recursive stuff but failed.

No need for recursion. Perl can do it for you.
# any help really appreciated!
#
# greez bernd (who just didn't see the solution)

use strict;

# one character
foreach my $a ('a'..'z','0'..'9') {
print "$a\n";
}

print join "\n", 'a'..'z', '0'..'9';
# two character
foreach my $a ('a'..'z','0'..'9') {
foreach my $b ('a'..'z','0'..'9') {
print "$a$b\n";
}
}

The values '0a' to '9z' are a bit annoying as one can't rely on Perl's
string auto-increment.

print join "\n", 'aa'..'zz',
'a0'..'a9';
map { my $a = $_; map { "$a$_" } 'a'..'z' } '0'..'9';
'00'..'99';
# tree character
foreach my $a ('a'..'z','0'..'9') {
foreach my $b ('a'..'z','0'..'9') {
foreach my $c ('a'..'z','0'..'9') {
print "$a$b$c\n";
}
}
}

Naturally, it gets longer and more annoying for three letter ranges.
# n character ???

You don't really need recursion. What you need is a function that
generates the next string item, so something that turns 'zz' into 'z0',
'99' into 'aaa' etc. So a program could look thusly:

sub next_item {
my ($i, $tail) = shift;

if (substr($i, -1, 1) eq 'z') {
substr($i, -1, 1, '0');
return $i;
}
if ($i =~ /^9+$/) {
return 'a' x (length($i)+1);
}
if (substr($i, -1, 1) eq '9') {
chop($i);
$i = next_item($i) . 'a';
return "$i";
}
if ($i =~ /\d.*[a-z]/) {
substr($i, -1, 1)++;
return $i;
}
return ++$i;
}

my $item = "a";
while ($item ne '999') {
print $item, "\n";
$item = next_item($item);
}

next_item() is slightly recursive, though. The recursion is used for the
case that an item ends on '9' in which case you get a carrier that
ripples from right to left until a character other than '9' is found.

Tassilo
 
A

Andrew Tkachenko

bernd wrote on 26 ÐоÑбрь 2004 16:50:
#!/usr/bin/perl -w
#
# hy group
#
# i feel really stupid. could it be that hard?
#
# i try to write a script to bruteforce the ASCII range. something
# like:
#
# a..z
# aa..zz
# aaa..zzz
# ...
#
# but there must be a smarter, solution than writing the same stuff
# over and over again. i'd tried some recursive stuff but failed.
#
# any help really appreciated!
#
# greez bernd (who just didn't see the solution)

use strict;

# one character
foreach my $a ('a'..'z','0'..'9') {
print "$a\n";
}

# two character
foreach my $a ('a'..'z','0'..'9') {
foreach my $b ('a'..'z','0'..'9') {
print "$a$b\n";
}
}

# tree character
foreach my $a ('a'..'z','0'..'9') {
foreach my $b ('a'..'z','0'..'9') {
foreach my $c ('a'..'z','0'..'9') {
print "$a$b$c\n";
}
}
}

# n character ???

You may try to play with Algorithm::GenerateSequence.

use Algorithm::GenerateSequence;

my $len = 3; #sequence length
my $gen = Algorithm::GenerateSequence->new(
map {['a' .. 'z', 0 .. 9]} (0 .. $len)
);

local $" = "";
while(my @c = $gen->next) {
print "@c\n";
}
 
B

Bill Smith

bernd said:
#!/usr/bin/perl -w
#
# hy group
#
# i feel really stupid. could it be that hard?
#
# i try to write a script to bruteforce the ASCII range. something
# like:
#
# a..z
# aa..zz
# aaa..zzz
# ...
#

This specification omits many details, the most important of which is
the order of the strings within each group.


# but there must be a smarter, solution than writing the same stuff
# over and over again. i'd tried some recursive stuff but failed.
#

As I have said in other threads, recursive solutions are probably never
"necessary" and seldom if ever efficient. Recursion can often be used
to compactly specify a function which would be awkward otherwise. A
perl implementation of such a spec can be almost indistinguishable from
the spec. This is certainly an advantage in program validation.

OK, I'll be honest. I never actually wrote the formal spec for this
one. Here is my recursive solution.

$ARGV[0] = 3 unless defined @ARGV;
my $N = $ARGV[0]-1;

my @SET = ('a'..'z', 0..9);

recurse(''); # Run the recursion



sub recurse{

my $prefix = $_[0];
if (length $prefix < $N){
recurse($prefix.$_) foreach @SET;
} else{
print $prefix.$_."\n" foreach @SET;
}

}

Note that the global "variable" names $N and @SET are in upper case to
emphasize that they are logically constant. The command line argument
(default 3) is the OP's "n". My $N is one less.


Bill
 
M

Michele Dondi

# but there must be a smarter, solution than writing the same stuff
# over and over again. i'd tried some recursive stuff but failed.
#
# any help really appreciated!
#
# greez bernd (who just didn't see the solution)

recursive, general purpose, certainly not terribly efficient!

sub range;
sub range {
my $n=shift;
return '' if $n == 0;
map { my $c=$_;
map $c.$_, range $n-1, @_ } @_;
}

print for range 3, 'a'..'z';


Michele
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top