Как в Perl генерировать случайные строки, состоящие из восьми шестнадцатеричных цифр?

Используя Perl, без использования каких-либо дополнительных модулей, которые не поставляются с ActivePerl, как я могу создать строку из 8 символов от 0 до F. пример 0F1672DA? Заполнение должно быть контролируемым, предпочтительно ровно 8 символов.

Дополнительные примеры типов строк, которые я хотел бы сгенерировать:

28DA9782
55C7128A

person unixman83    schedule 26.04.2012    source источник
comment
Гольф: perl -e'print[0..9,A..F]->[rand 16]for 1..8'   -  person daxim    schedule 26.04.2012
comment
Зачем минусовать? Мне нужно научиться программированию. Для чего нужен stackoverflow, если не такие вопросы?   -  person unixman83    schedule 26.04.2012
comment
Я не голосовал за ваш пост. Однако, как правило, исключение каких-либо модулей CPAN не приветствуется. Кроме того, ожидается, что вы предпримете некоторые усилия, чтобы найти собственное решение, и попросите помощи в этом, а не ожидаете, что другие дадут вам готовые решения.   -  person Sinan Ünür    schedule 26.04.2012
comment
CPAN — это боль для ActiveState. :) Я рекомендую Strawberry Perl.   -  person Quentin    schedule 26.04.2012
comment
@Quentin - у меня не было особых проблем с CPAN на AS perl. Компилятор C и dmake поставляются через ppm (ppm inst dmake, ppm inst mingw). Я предпочитаю cpanm для установки модулей напрямую из cpan (ppm inst App::cpanminus).   -  person bvr    schedule 26.04.2012


Ответы (4)


В принципе, вы должны быть в состоянии сделать

#!/usr/bin/env perl

use strict; use warnings;

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

Однако вы можете обнаружить, что — по крайней мере, в некоторых системах с некоторыми perls (если не во всех) — диапазон rand ограничен 32 768 значениями.

Вы также можете изучить исходный код String::Random, чтобы научиться генерировать случайные строки, удовлетворяющие другим условиям.

Однако мое предостережение против использования встроенного rand в системе Windows остается в силе. См. Math::Random::MT для высококачественного ГСЧ.

#!/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: Проблема с рандом Perl в Windows была исправлена ​​в версии 5.20:

Это означало, что качество случайных чисел Perl будет варьироваться от платформы к платформе, от 15-битной функции rand() в Windows до 48-битной на платформах POSIX, таких как Linux с drand48().

Теперь Perl использует собственную внутреннюю реализацию drand48() на всех платформах. Это не делает perl rand криптографически безопасным. [перл # 115928]

person Sinan Ünür    schedule 26.04.2012
comment
Наверняка есть плагин, поставляемый с ActivePerl, который преодолевает ограничение rand? - person unixman83; 26.04.2012
comment
Будет ли решение использовать rand для 1 цифры за раз? Ваш второй пример делает это? - person unixman83; 26.04.2012
comment
Да, второй метод генерирует строку по одной цифре за раз, используя адаптируемый @set, аналогичный методу @Oleg (за который я проголосовал). - person Sinan Ünür; 26.04.2012

Общий пример, допускающий любой диапазон символов:

my @chars = ('0'..'9', 'A'..'F');
my $len = 8;
my $string;
while($len--){ $string .= $chars[rand @chars] };
print "$string\n";
person Oleg V. Volkov    schedule 26.04.2012

sprintf("%08X", rand(0xFFFFFFFF))

некоторые люди упомянули оконный предел ранда с MAX-значением ранда (0x7FFF) или ранда (32768) десятичного числа, я бы преодолел это с помощью двоичного оператора сдвига '‹‹'

# 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) )
      );

Но я рассматриваю это только как академический, потому что это действительно неуклюжий код, который трудно понять.
Я бы не стал использовать это в реальном коде, только если скорость важнее всего.
Но, возможно, это самое быстрое решение. и он демонстрирует схему для преодоления ограничения функции rand() под окнами...

person Lutz L.    schedule 26.04.2012
comment
По словам @Sinan, это не сработает. Диапазон rand только до 32 768! - person unixman83; 26.04.2012
comment
Мое утверждение было несколько слабее: * По крайней мере, в некоторых системах Windows диапазон rand может быть ограничен 32 768 значениями. - person Sinan Ünür; 26.04.2012
comment
Думаю, Sinan Ünür должен написать отчет об ошибке, если это действительно так. А возвращаемые значения rand() находятся в наборе всего из 32768 различных чисел. perldoc -f говорит мне, что rand должен возвращать дробное число. Я думаю, что мое решение правильное в соответствии с документацией и моим собственным тестом. - person Lutz L.; 26.04.2012
comment
Почему вы не можете отправить отчет об ошибке? :) - person brian d foy; 27.04.2012
comment
Я не могу воспроизвести эту ошибку. Я не люблю Вин :). Однажды я нашел ошибку, но она исчезла после обновления Perl... я опоздал. - person Lutz L.; 27.04.2012
comment
@ЛуцЛ. Я исхожу из слов Синана, и, честно говоря, исходя из поведения ActiveState под Windows, я ему верю. Как ты можешь работать под линуксом, у тебя должно быть плохое железо (или суперкомпьютер ;) ). - person unixman83; 27.04.2012
comment
@Sinan: я думаю, что это ошибка, и ее стоит отследить. Просто запустите %h=map{ rand()=›´´ } 1..1_000_000; напечатать 0+keys(%h); и, пожалуйста, сообщите об этом, это поможет создать надежный Perl для Windows. - person Lutz L.; 27.04.2012
comment
Лутц и @briandfoy Проблема связана с rand реализация, поставляемая с Windows: Функция rand возвращает псевдослучайное целое число в диапазоне от 0 до RAND_MAX (32767) Это ограничение платформы. Даже если какая-то сборка perl когда-нибудь в будущем изменится на какую-то другую rand, принцип останется: если вам небезразлично, что производит rand, используйте то, что имеет определенные хорошие свойства. - person Sinan Ünür; 27.04.2012

Используйте sprintf для преобразования чисел в шестнадцатеричный формат.

$foo .= sprintf("%x", rand 16) for 1..8;
person Quentin    schedule 26.04.2012