cghost23 has asked for the wisdom of the Perl Monks concerning the following question:

i am writing code that will generate a given number of random characters and stuff them into a variable. here is the relevant code:
$minlength=5; $maxlength=15; $rlength=$minlength+=int(rand($maxlength)); @vchars=(a..z,A..Z,0..9); while(length($newvar) < $rlength) { $char=$vchars[int(rand($#vchars))]; $newvar.=$char } print $newvar
so basically $rlength holds a random whole number between 5 and 15 and @vchars holds the characters i want to use to generate the random word..then as long as $newvar is less than $rlength ($newvar is 0 at this point), a number between 0 and the number of characters in @vchars is generated and used as the array subscript for @vchars (effectively selecting a random element from @vchars). the result of this is assigned to $char, then $char is appened to $newvar...this repeats if $newvar is less than the random length...HOWEVER..if i do
while(@whatever) { s/blah/rwg()/ge; }
somewhere else in the code, where rwg is the name of the subroutine that contains the random word generation code at the top...instances of 'blah' get replaced with the same string of random characters, just of variable length. like 'blah blah' would become 'jhGsdF jhGs'. it seems the random element selection code only runs once or something..it just changes the length. this has been bothering me for days. thanks a lot. -cghost23

Replies are listed 'Best First'.
Re: random number generation problem
by tadman (Prior) on Apr 27, 2001 at 01:20 UTC
    The problem is that you forgot to declare '$newvar' as a local variable, so each time through the loop the result of the previous assignment is still there.

    Switch it to my($newvar), or reset it each time.

    Not having local variables also means that $minlength is incremented by ('+=') a random number each time. If you want to pick a number from 5 to 15, you are a little off track.

    As a creative suggestion, instead of doing all that work, why not just this?
    my(@vchars) =(a..z,A..Z,0..9); sub rwg { return join ('', map { $vchars[int(rand($#vchars+1))] } 5 .. 5+int(rand(10))); }
    Change 5 to $minlength, 10 to ($maxlength-$minlength) if so desired.

    Additionally, remember that rand() picks a number up to the maximum, which in this case is $#vchars, so the last letter will probably not get picked unless you +1 it.
      thanks a lot for the code, but
      return join ('', map { $vchars[int(rand($#vchars+1))] } 5 .. 5+int(rand(10)));
      seems to also return strings less than 5 chars longs
        Would you believe it if I said that it should read:
        1 .. 5+int(rand(10)))
        Since we aren't counting from five to some number in the range of 5-15, but from 1!

        Thanks to cghost23 and Chmrr for the tip.
Re: random number generation problem
by tadman (Prior) on Apr 27, 2001 at 01:15 UTC
    Don't forget that when you use 'rand' you have to 'srand' to initialize the random number generator:     srand (time ^ $$ | $$ << 4); If you're really concerned about security, I would strongly recommend something better than that, but for trivial exercises, that should do just fine.
      Don't forget that when you use 'rand' you have to 'srand' to initialize the random number generator:
      As of 5.5 and later, you don't have to. Done for you automatically. You may want to randomize it to something a little more crypto-secure, but it will start in a spun place differently each time.

      -- Randal L. Schwartz, Perl hacker

      Please don't. As others have noted, Perl often does this for you. What they haven't noted is that when Perl does, it does a better job than you did.

      For more details and suggestions of how to do it in a way that works for both old and new Perl, see Perl's auto srand() RE: a random sort of list.

              - tye (but my friends call me "Tye")
        During testing, I found it odd that rand() was producing random numbers without the use of srand(), which for the longest time was a strict requirement. Now, I would have deleted the node, but by the time I got around to doing that, the thread was growing like a weed.

        Just another one of those incredible things that changed but nobody really knew.

      A correction: perldoc -f srand says:

      In fact, it's usually not necessary to call
      `srand' at all, because if it is not called
      explicitly, it is called implicitly at the first
      use of the `rand' operator.
      

      But I note:

       However, this was not
                     the case in version of Perl before 5.004

      So there ya go.