2

I have a PHP function that can generate alpha-numeric string with given length. The function works fine. But the generated string includes digits sometimes, and sometimes it does not include digits. I want that the string must consist of number and alpha every time. Need suggestion for that. Here is the code of the function:

public static function GenerateAlphaNumString($length=0) {
        $characterPool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $randomString = '';

        for ($i = 0; $i < $length; $i++) {
            $randomString .= $characterPool[rand(0, strlen($characterPool) - 1)];
        }

        return $randomString;
    } 
3
  • 1
    How many letters and how many digits? And you can't have both if $length < 2. Commented Jan 31, 2016 at 14:19
  • If it is supposed to be random, you can't expect it to always include digits ... Also, rand() is not really random. Commented Jan 31, 2016 at 14:20
  • No limit for digit. But the string should contain minimum one digit. Unlike now, because sometimes it generates string without any digit. Commented Jan 31, 2016 at 14:22

4 Answers 4

4

A full example, offering flexibility:

<?php

class StringGenerator
{
  private $characterPool = [
    'numeric' => '0123456789',
    'alpha' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
  ];

  function generateRandomString($length, $pool) {
    $randomString = '';
    for ($i = 0; $i  < $length; $i++) {
      $randomString .= $this->characterPool[$pool][rand(0, strlen($this->characterPool[$pool]) - 1)];
    }
    return $randomString;
  }

  function generateAlphaNumString($length=0, $numeric=0) {
    return str_shuffle(
      $this->generateRandomString($numeric, 'numeric') .
      $this->generateRandomString($length-$numeric, 'alpha')
    );
  }
}

$generator = new StringGenerator;
for ($c=0; $c<=10; $c++) {
  var_dump($generator->generateAlphaNumString(10, 5));
}

The output is something like:

string(10) "J5F4FQX480"
string(10) "Z2g647pO9a"
string(10) "159Mf8GEL3"
string(10) "B5P57I42hN"
string(10) "Us97v5cg80"
string(10) "34VEHY825t"
string(10) "V6Ei5p06s1"
string(10) "YS5noD5127"
string(10) "4dJ4Y4G4q4"
string(10) "C8V7W3Q2G9"
string(10) "gu28g99H9d"
Sign up to request clarification or add additional context in comments.

3 Comments

This fixes the number of generated digits (5 in this case), which makes it a bit less random than the original.
@trincot That is indeed true, it is how I understood the OPs question, though I agree this can be seen in different ways... Nothing speaks against randomizing the number of numericals in the final call, though...
A much better solution
3

You could do it like this:

// Add a quick exit:
if ($length <= 0) return '';

// Produce all characters except the last one: 
for ($i = 0; $i < $length-1; $i++) {
    $randomString .= $characterPool[rand(0, strlen($characterPool) - 1)];
}

// Check if string contains a digit, if not, reduce range 
// for generating last character so it can only be a digit:
$lastRange = preg_match("/\d/", $randomString) ? strlen($characterPool) : 10;
// choose random position, and insert last character in there:
$randomString = substr_replace($randomString, $characterPool[rand(0, $lastRange-1)], 
                               rand(0, $length-1), 0);

return $randomString;

This method will maintain the probability for each character's occurrence as close as possible to the original. It does not force digits to be grouped together either.

Obviously the right mix can only be generated when the given length is at least 2.

4 Comments

Thanks. It works great and clean. Thank you so much. But can I randomize the position of the number when I forced to enter number?
Yes, that is possible. I improved the code to insert last chosen character at random position.
Thanks for the changes and comments in the code. The comments helped me so much as I am a newbie. :)
Even for non-newbie, comments are an essential part of good code. Glad you can appreciate it!
3

This should do the trick

$characterPool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$randomString = '';
$numberscount = rand(1,$length-1);
for ($i = 0; $i < $numberscount; $i++) {
    $randomString .= rand(0,9);
}
for ($i = 0; $i < ($length - $numberscount); $i++) {
    $randomString .= $characterPool[rand(0, strlen($characterPool) - 1)];
}

it always prints a character when $length = 1 though.

1 Comment

This tends to concentrate digits at the start of the string which makes it a little bit less random.
2

Add the following before you return the string

If(!preg_match( '/([0-9]+)/', $randomString) {
     return self::GenerateAlphaNumString($length);
}

If there are no numbers in your string just recall same function until there is.

3 Comments

I'd call this somewhat inefficient. Kind of the famous "random sort algorithm"...
Nice! You should add return before that recursive call though.
Good spot. Edited my answer. If efficiency is a major concern this may not be the best solution but probability of having to iterate second time is reasonably small so for most cases I reckon this is ok

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.