The bellow functions are used to generate a string with random characters, and they have a parameter to specify the string length.
The string can be composed of letters, numbers or a conjunction of both.
I've been using this for a very long time now, and currently, I look at it and it seems to damn extensive for the end result.
Functions
function assign_rand_value($num) {
// accepts 1 - 36
switch($num) {
case "1" : $rand_value = "a"; break;
case "2" : $rand_value = "b"; break;
case "3" : $rand_value = "c"; break;
case "4" : $rand_value = "d"; break;
case "5" : $rand_value = "e"; break;
case "6" : $rand_value = "f"; break;
case "7" : $rand_value = "g"; break;
case "8" : $rand_value = "h"; break;
case "9" : $rand_value = "i"; break;
case "10" : $rand_value = "j"; break;
case "11" : $rand_value = "k"; break;
case "12" : $rand_value = "l"; break;
case "13" : $rand_value = "m"; break;
case "14" : $rand_value = "n"; break;
case "15" : $rand_value = "o"; break;
case "16" : $rand_value = "p"; break;
case "17" : $rand_value = "q"; break;
case "18" : $rand_value = "r"; break;
case "19" : $rand_value = "s"; break;
case "20" : $rand_value = "t"; break;
case "21" : $rand_value = "u"; break;
case "22" : $rand_value = "v"; break;
case "23" : $rand_value = "w"; break;
case "24" : $rand_value = "x"; break;
case "25" : $rand_value = "y"; break;
case "26" : $rand_value = "z"; break;
case "27" : $rand_value = "0"; break;
case "28" : $rand_value = "1"; break;
case "29" : $rand_value = "2"; break;
case "30" : $rand_value = "3"; break;
case "31" : $rand_value = "4"; break;
case "32" : $rand_value = "5"; break;
case "33" : $rand_value = "6"; break;
case "34" : $rand_value = "7"; break;
case "35" : $rand_value = "8"; break;
case "36" : $rand_value = "9"; break;
}
return $rand_value;
}
function get_rand_alphanumeric($length) {
if ($length>0) {
$rand_str="";
for ($i=1; $i<=$length; $i++) {
mt_srand((double)microtime() * 1000000);
$num = mt_rand(1,36);
$rand_str .= assign_rand_value($num);
}
}
return $rand_str;
}
function get_rand_numbers($length) {
if ($length>0) {
$rand_str="";
for($i=1; $i<=$length; $i++) {
mt_srand((double)microtime() * 1000000);
$num = mt_rand(27,36);
$rand_str .= assign_rand_value($num);
}
}
return $rand_str;
}
function get_rand_letters($length) {
if ($length>0) {
$rand_str="";
for($i=1; $i<=$length; $i++) {
mt_srand((double)microtime() * 1000000);
$num = mt_rand(1,26);
$rand_str .= assign_rand_value($num);
}
}
return $rand_str;
}
Usage:
Basically I have a main function with the values, then I call secondary functions to build my string based on the length parameter:
Letters:
$str = get_rand_letters(8); // Only Letters
Numbers:
$str = get_rand_numbers(8); // Only Numbers
AlphaNumeric:
$str = get_rand_alphanumeric(8); // Numbers and Letters
My question:
How would I go, as to reduce the amount of code, keeping the end result the same?
1 Answer 1
First: I'm sure there's even simpler way than this (i.e. a library that just does what you need, period), but heck, I figured I'd try. Been years since I spent my days with PHP (don't particularly miss it).
Anyway, skip the whole switch
lookup. (削除) See Rene Geuze's comment below; while chr()
will take an int and give you its ASCII value. The 97-122 range (inclusive) is a-z (65-90 is A-Z). As for numbers, well, that's what a random function gives you - no need to look that up. (削除ここまで)chr
works just fine, range
is indeed more readable.
function get_rand($min, $max) {
mt_srand((double) microtime() * 1000000);
return mt_rand($min, $max);
}
function get_rand_alphanumeric($length) {
$alnum = "";
$range = range("a", "z");
$limit = count($range) + 9;
while(strlen($alnum) < $length) {
$rand = get_rand(0, $limit);
if( $rand < 10 ) {
$alnum .= $rand;
} else {
$alnum .= $range[$rand - 10];
}
}
return $alnum;
}
function get_rand_numbers($length) {
if( $length <= 8 ) { // avoid int overflow
return (string) get_rand(pow(10, $length-1), pow(10, $length));
} else {
$numbers = "";
while(strlen($numbers) < $length) $numbers .= get_rand_numbers(8);
return substr($numbers, 0, $length);
}
}
function get_rand_letters($length) {
$letters = "";
$range = range("a", "z");
$limit = count($range) - 1;
while(strlen($letters) < $length) $letters .= $range[get_rand(0, $limit)];
return $letters;
}
You get results like this
get_rand_alphanumeric(42) => upop8eoome0y0av2qav1j7yn5linyjshiurc8lbjja
get_rand_numbers(42) => 365818982423371436493339856184748778003731
get_rand_letters(42) => abfmthyuxdlganhfthebfjaugeeoniqawocgavowpx
Edit I just realized that your original alphanumeric function will pick randomly from your entire list, meaning it's 2.6 times more likely that the pick will be a letter. I edited mine to do the same to keep the results similar.
Also, the calls to mt_srand
are by far the most expensive operation. Consider calling it less frequently, if speed is a concern. If I omit it, the functions above are 7.5-10x faster than the original; if I leave it as you see in the code, the functions are still faster, but only very marginally so (1.1x to 1.4x). In either case, get_rand_numbers
obviously sees the biggest speedup since there's not lookup going on.
Edit 2 Replaced chr
usage with a range
array, re: the comments
-
1\$\begingroup\$ Using the range() function is probably more human readable than using chr. Used by filling one array with range and just pick randomly from the array instead. \$\endgroup\$René– René2012年10月04日 16:41:03 +00:00Commented Oct 4, 2012 at 16:41
-
\$\begingroup\$ @ReneGeuze Good point. Adding it to my answer, thanks \$\endgroup\$Flambino– Flambino2012年10月04日 17:15:28 +00:00Commented Oct 4, 2012 at 17:15