0

我对生成随机字符的两种算法感到困惑。我有四种字符类型,小写,大写,数字和特殊字符。根据请求的随机字符的类型,它应该产生字符。例如:

  • 如果请求的是纯小写、大写、数字或特殊字符,则应仅从每种类型中随机选择该值。
  • 如果请求的是小写和数字,则应从这两种类型的混合字符串中选择。
  • ETC

我对混合字符类型采用的算法如下:

  1. 从每种类型中选择具有所需字符长度的随机字符串。
  2. 连接这些字符串,然后从新字符串中再次选择随机字符。

我认为该算法确保了样本空间中每种类型可用的概率相等。但是,在某些情况下,混合类型的结果字符串可能没有字符串中显示的任何一种类型,并且在某些许多情况下,我们可能会得到一些重复的字符。

还有另一种算法依赖于在选择随机字符串之前预先混合类型,但是,更可能出现一种类型的缺失,但减少了重复。

我需要知道是否有另一种算法可以在每种类型的呈现和减少重复之间提供平衡?

以下是实现我首先提到的算法的代码。它是 CakePHP 1.2.x 组件,可以在这里找到一个工作示例:

<?php
class RandomStringComponent extends Object{
  var $name = 'RandomString';
  var $lowerCase = 'qwertyuiopasdfghjklzxcvbnm';
  var $upperCase = 'ASDFGHJKLQWERTYUIOPZXCVBNM';
  var $numbers = '9874563210';
  var $specialChars = '!@#$%)-+/}[<>~=,;:|`{.?]^&*(';
  var $outputForm = 'LcUcNuSp';
  var $settings = array();
  var $controller = null;      

  var $_defaults = array(
      'outputForm' => 'LcUcNuSp',
      'length' => 6
  );

  function initialize(&$controller, $settings){
    $this->settings = array_merge($this->_defaults, $settings);

  }

  function getRand($l = null){
    if (is_null($l)) $l = $this->settings['length'];
    switch ($this->settings['outputForm']){
      case 'Lc':
        return $this->_Lc($l);
        break;
      case 'Uc':
        return $this->_Uc($l);
        break;
      case 'Sp':
        return $this->_Sp($l);
        break;
      case 'Nu':
        return $this->_Nu($l);
        break;
      case 'LcUc':
        return $this->_setRand($this->_Lc($l).$this->_Uc($l),$l);
        break;
      case 'LcNu':
        return $this->_setRand($this->_Lc($l).$this->_Nu($l),$l);
        break;
      case 'UcNu':
        return $this->_setRand($this->_Uc($l).$this->_Nu($l),$l);
        break;
      case 'LcUcNu':
        return $this->_setRand($this->_Lc($l).$this->_Uc($l).$this->_Nu($l),$l);
        break;
      default:
        return $this->_setRand($this->_Lc($l).$this->_Uc($l).$this->_Nu($l).$this->_Sp($l),$l);
        break;
    }
  }


  function _Lc($l){
    $output = '';
    for ($i = 0; $i < $l; $i++){      
      $output .= $this->lowerCase[mt_rand(0, strlen($this->lowerCase)-1)];    
    }
    return $output;
  }
  function _Uc($l){
    $output = '';
    for ($i = 0; $i < $l; $i++){
      $output .= $this->upperCase[mt_rand(0, strlen($this->upperCase)-1)];    
    }
    return $output;
  }
  function _Sp($l){
    $output = '';
    for ($i = 0; $i < $l; $i++){
      $output .= $this->specialChars[mt_rand(0, strlen($this->specialChars)-1)];      
    }
    return $output;
  }
  function _Nu($l){
    $output = '';
    for ($i = 0; $i < $l; $i++){
      $output .= $this->numbers[mt_rand(0, strlen($this->numbers)-1)];    
    }
    return $output;
  }

  function _setRand($str, $l){

    $output = '';
    for ($i = 0; $i < $l; $i++){
      $output .= $str[mt_rand(0, strlen($str)-1)];    
    }
    return $output; 
  }  
}
?>
4

1 回答 1

2

您可以通过不更换采样来消除重复。如果你想要“一些”重复,你可以对一些 k 值进行重复采样,将其附加到原始列表中,然后在不替换的情况下进行采样。

例如:lowerCase = 'qwertyuiopasdfghjklzxcvbnm'

sampledLowercase = 从小写中采样 5 个字母 = 'abbcd'

它们从小写+sampledLowercase 中采样而无需替换。

这里找到重复字符的概率约为 5/(26+5) = 5/31。sampledLowercase 的长度越长,出现重复字母的概率就越高。

于 2013-05-03T17:45:51.890 回答