10

Using Perl, without using any extra modules that don't come with ActivePerl, how can I create a string of 8 characters from 0-F. example 0F1672DA? The padding should be controllable and exactly 8 characters is preferable.

More examples of the kinds of strings I would like to generate:

28DA9782
55C7128A
unixman83
  • 8,261
  • 10
  • 62
  • 98
  • 5
    Golf: `perl -e'print[0..9,A..F]->[rand 16]for 1..8'` – daxim Apr 26 '12 at 15:42
  • 1
    Why downvoting? I do need to learn programming. What is stackoverflow for if not these kind of questions? – unixman83 Apr 26 '12 at 15:44
  • 4
    I did not vote your post down. However, generally, ruling out any CPAN modules is not looked upon favorably. Also, you are expected to make some effort to come up with a solution of your own, and ask for help with that rather than expecting others to give you canned solutions. – Sinan Ünür Apr 26 '12 at 15:51
  • 1
    CPAN is a pain on ActiveState. :) I recommend Strawberry Perl. – Quentin Apr 26 '12 at 16:06
  • @Quentin - I did not have much problems with CPAN on AS perl. They ship C compiler and dmake via ppm (`ppm inst dmake`, `ppm inst mingw`). I prefer `cpanm` for installing modules directly from cpan (`ppm inst App::cpanminus`). – bvr Apr 26 '12 at 16:43

4 Answers4

19

In principle, you ought to be able to do

#!/usr/bin/env perl

use strict; use warnings;

for (1 .. 10) {
    printf "%08X\n", rand(0xffffffff);
}

However, you may find out that —at least on some systems with some perls (if not all)— the range of rand is restricted to 32,768 values.

You can also study the source code of String::Random to learn how to generate random strings satisfying other conditions.

However, my caution against using the built in rand on Windows system still stands. See Math::Random::MT for a high quality RNG.

#!/usr/bin/env perl

use strict; use warnings;

my @set = ('0' ..'9', 'A' .. 'F');
my $str = join '' => map $set[rand @set], 1 .. 8;
print "$str\n";

PS: The issue with Perl's rand on Windows was fixed in 5.20:

This meant that the quality of perl's random numbers would vary from platform to platform, from the 15 bits of rand() on Windows to 48-bits on POSIX platforms such as Linux with drand48().

Perl now uses its own internal drand48() implementation on all platforms. This does not make perl's rand cryptographically secure. [perl #115928]

Community
  • 1
  • 1
Sinan Ünür
  • 113,391
  • 15
  • 187
  • 326
10

General example, allowing any range of characters:

my @chars = ('0'..'9', 'A'..'F');
my $len = 8;
my $string;
while($len--){ $string .= $chars[rand @chars] };
print "$string\n";
Oleg V. Volkov
  • 19,811
  • 3
  • 40
  • 60
5
sprintf("%08X", rand(0xFFFFFFFF))

some people mentioned the windows-limit of rand with the MAX-Value of rand(0x7FFF) or rand(32768) decimal, i would overcome this with binary shifting-operator '<<'

# overcomes the windows-rand()-only-works-with-max-15bit-(32767)-limitation:
#   needed 8*4==32bit random-number:
#     first get the 15 high-significant bits shift them 17bits to the left,
#     then the next 15bits shifted 2 bits to the left,
#     then the last 2 bits with no shifting:
printf( '%08X', (
    (rand(0x8000)<<17) + (rand(0x8000)<<2) + rand(0b100) )
      );

But i consider this only as academic, because it is really awkward code which is difficult to understand.
I would not use this in real-life code, only if speed mater the most.
But maybe its the fastest solution and it's demonstrating a schema to overcome the limitation of the rand()-function under windows...

Lutz L.
  • 379
  • 2
  • 6
  • This won't work according to @Sinan. `rand`'s range is only to 32,768! – unixman83 Apr 26 '12 at 15:49
  • 3
    My statement was somewhat weaker: *On at least some Windows systems, `rand`'s range might be limited to 32,768 values. – Sinan Ünür Apr 26 '12 at 15:54
  • 1
    I think Sinan Ünür should file a bug-report, if this is really true. And rand() returning values are in the set of only 32768 different numbers. perldoc -f tells me rand should return a fractional number. I think my solution is correct according to the documentation, and my own test. – Lutz L. Apr 26 '12 at 18:15
  • 3
    Why can't you file a bug report? :) – brian d foy Apr 26 '12 at 21:38
  • I can't reproduce this error. I don't like Win :). Once i found a bug but it was gone after updating Perl ... i was to late. – Lutz L. Apr 26 '12 at 22:25
  • @LutzL. I am going by the words of Sinan, and frankly, based on ActiveState's behavior under Windows, I believe him. How can you work under Linux, u must have poor hardware (or a supercomputer ;) ). – unixman83 Apr 27 '12 at 00:38
  • @Sinan: I think its a bug, and worth to trace it. Just run %h=map{ rand()=>´´ } 1..1_000_000; print 0+keys(%h); and please report it, this will help to build a reliable perl on windows. – Lutz L. Apr 27 '12 at 15:43
  • 1
    Lutz and @briandfoy The issue is with the [`rand` implementation that comes with Windows](http://msdn.microsoft.com/en-us/library/398ax69y%28v=vs.80%29.aspx): *The rand function returns a pseudorandom integer in the range 0 to `RAND_MAX` (`32767`)* It's a platform limitation. Even if some build of `perl` some time in the future changed to some other `rand`, the principle would remain: If you care about what `rand` produces, then use something that has defined good properties. – Sinan Ünür Apr 27 '12 at 16:34
4

Use sprintf to convert numbers to hex.

$foo .= sprintf("%x", rand 16) for 1..8;
Sinan Ünür
  • 113,391
  • 15
  • 187
  • 326
Quentin
  • 800,325
  • 104
  • 1,079
  • 1,205