In Perl, how can I generate random strings consisting of eight hex digits?
Asked Answered
A

5

17

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
Ariellearies answered 26/4, 2012 at 15:33 Comment(5)
Golf: perl -e'print[0..9,A..F]->[rand 16]for 1..8'Gramps
Why downvoting? I do need to learn programming. What is stackoverflow for if not these kind of questions?Ariellearies
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.Antibiotic
CPAN is a pain on ActiveState. :) I recommend Strawberry Perl.Napkin
@Napkin - 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).Colville
M
23

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]

Minus answered 26/4, 2012 at 15:39 Comment(3)
Surely there is a plugin that comes with ActivePerl that overcomes the limit of rand?Ariellearies
Would a solution be using rand for 1 digit at a time? Does your second example do this?Ariellearies
Yes, the second method does generate the string one digit at a time using an adaptable @set similar to @Oleg's method (which I voted up).Antibiotic
G
12

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";
Gnarled answered 26/4, 2012 at 15:40 Comment(0)
N
6

Use sprintf to convert numbers to hex.

$foo .= sprintf("%x", rand 16) for 1..8;
Napkin answered 26/4, 2012 at 15:39 Comment(0)
B
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...

Balustrade answered 26/4, 2012 at 15:40 Comment(8)
This won't work according to @Sinan. rand's range is only to 32,768!Ariellearies
My statement was somewhat weaker: *On at least some Windows systems, rand's range might be limited to 32,768 values.Antibiotic
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.Balustrade
Why can't you file a bug report? :)Arteriotomy
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.Balustrade
@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 ;) ).Ariellearies
@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.Balustrade
Lutz and @briandfoy The issue is with the rand implementation that comes with Windows: 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.Antibiotic
A
1

From the "golf" comment by daxim:

perl -e'print[0..9,A..F]->[rand 16]for 1..8'
Acree answered 26/4, 2012 at 15:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.