delphi生成随机PIN码

时间:2016-05-23 10:31:07

标签: delphi

我想生成指定长度的随机数。

function _RandomCode(const CodeLen: Word): Word;
begin
  Result := Random(CodeLen);
  repeat
    Result := Result + Random(CodeLen) + 1;
  until (Length(IntToStr(Result)) = CodeLen)
end;

结果始终为10000

3 个答案:

答案 0 :(得分:6)

虽然我投票决定将这个问题作为重复发表,但在这里再次考虑的是使其与纯随机函数应用程序不同的方面。

首先,您的代码没有提供您期望的结果,因为您小数字(0 .. codelen-1)添加到每个循环的结果中,当值达到时停止转换为字符串时包含codelen个字符数的值。对于codelen = 5,这将始终停留在10000 .. 10003.如果您已经调试了调试器中的代码,您很快就会意识到为什么会得到您所做的结果。

其次,受@MichaelVincent的启发,PIN码通常允许前导零,f.ex。 '0123'。因此,我认为这个问题也是如此。由于整数类型结果不能保存前导零,我建议您使用string类型结果。

仅在启动应用程序时调用Randomize一次。

function _RandomCodeStr(const CodeLen: Word): string;
var
  n: integer;
begin
  SetLength(Result, CodeLen);
  for n := 1 to CodeLen do
    Result[n] := Char(ord('0')+ Random(10));
end;

我更改了函数的名称以反映它返回一个字符串。

根据要求增加:

关于Randomize功能(或分配RandSeed)。它在文档中解释:

  

Randomize使用a初始化内置随机数生成器   随机值(从系统时钟获得)。随机数   应该通过调用Randomize或者通过调用初始化生成器   为RandSeed分配一个值。

     

不要将循环中的Randomize调用与调用   随机功能。通常,Randomize在所有之前只调用一次   调用随机。

如果您将_RandomCodeStr功能放在一个单独的单元中,则可以将Randomize的呼叫置于该单元initialization部分。

答案 1 :(得分:3)

您的代码失败的原因:您正在添加小值(1..5),直到位数达到5.您始终获得10000的原因是您在启动时永远不会调用Randomize。这意味着您的“随机”系列始终是相同的。

改为使用RandomRange

  

返回指定范围内的随机整数。

     

RandomRange 从AFrom和ATo(不包括)之间的范围返回一个随机整数。 RandomRange 可以处理负范围(其中AFrom大于ATo)。

     

要初始化随机数生成器,在对 RandomRange 进行任何调用之前,添加一个调用Randomize或为RandSeed变量赋值。

function _RandomCode(const CodeLen: Word): Cardinal;
// CodeLen is 1,2,3 etc.
begin 
  Result := RandomRange(0,Trunc(IntPower(10,CodeLen)));
end;

我假设PIN码中可以接受前导零,否则将第一个参数设置为合适的值(IntPower(10,CodeLen-1))。

要将具有固定长度和可能的前导零的数字转换为字符串,请使用:

Format('%.*d',[CodeLen,_RandomCode(CodeLen)])

答案 2 :(得分:1)

使用randomize分开的两个音符(但只有一次!!!),如Tom Brunberg所指出的

1)Random不是加密安全的PRNG,因此使用它来生成随机(如不可预测的)PIN码是不太合适的想法。

2)你的循环既慢又安全性差(通过连续多次调用Random会导致其统计数据累积减少随机性)。 它可能是无限期的。如果一个时刻长度超过CodeLen怎么办?它永远不会缩小,循环永远不会结束;直到整数边界至少环绕。

为了让它更好一点,你可以这样做:

function _PseudoRandomCode(const CodeLen: Word): Word;
var s: string; i: integer; c: char;
begin
  SetLength(s, CodeLen); 
  for i := 1 to CodeLen do begin
    c := '0';
    Inc( c, random(10) ); // + 0..9
    s[i] := c;
  end;
  Result := StrToInt(s);
end;

或者像那样

function _PseudoRandomCode(const CodeLen: Word): Word;
var i,j: integer; 
begin
  i := 1; // 10^0
  for j := 1 to CodeLen do
      i := 10 * i; 
  // now i = 10^(CodeLen+1) that is '1' and CodeLen of zeroes.

  Result := Random( i );
end;

虽然我最好让函数返回string值而不是word值。

function _PseudoRandomCode(const CodeLen: Word): String;
var s: string; i: integer; c: char;
begin
  SetLength(s, CodeLen); 
  for i := 1 to CodeLen do begin
    c := '0';
    Inc( c, random(10) ); // + 0..9
    s[i] := c;
  end;
  Result := s;
end;

function _PseudoRandomCode(const CodeLen: Word): string;
var i,j: integer; 
begin
  i := 1; // 10^0
  for j := 1 to CodeLen do
      i := 10 * i; 
  // now i = 10^(CodeLen+1) that is '1' and CodeLen of zeroes.

  Result := IntToStr(Random( i ));
  if Length(Result) < CodeLen then
    Result := StringOfChar('0', CodeLen - Length(Result)) + Result;
end;

例如_RandomCode(4) = 25,你会怎么做?你必须在你使用它的每个地方用该函数之外的零填充PIN代码!最好在功能内部进行一次。