我正在与Dancer一起写一个非常小的URL缩短器。它使用REST插件将发布的URL存储在数据库中,该数据库具有六个字符的字符串,用户可以使用该字符串访问短路的URL。
现在我对我的随机字符串生成方法有点不确定。
sub generate_random_string{
my $length_of_randomstring = shift; # the length of
# the random string to generate
my @chars=('a'..'z','A'..'Z','0'..'9','_');
my $random_string;
for(1..$length_of_randomstring){
# rand @chars will generate a random
# number between 0 and scalar @chars
$random_string.=$chars[rand @chars];
}
# Start over if the string is already in the Database
generate_random_string(6) if database->quick_select('urls', { shortcut => $random_string });
return $random_string;
}
这会生成一个六字符串,如果生成的字符串已经在数据库中,则会递归调用该函数。我知道有63 ^ 6个可能的字符串,但如果数据库收集更多条目,这将需要一些时间。也许它会变成一个几乎无限的递归,我想阻止它。
是否有办法生成唯一的随机字符串,以防止递归?
提前致谢
答案 0 :(得分:5)
我们真的不需要手动波动你的函数有多少次迭代(或递归)。我相信在每次调用时,预期的迭代次数是按地理分布的(即第一次成功之前的试验次数由geomtric distribution控制),其平均值为1 / p,其中p是成功找到未使用的概率串。我相信p只是1 - n / 63 ^ 6,其中n是当前存储的字符串的数量。因此,我认为你需要在数据库中存储300亿个字符串(~63 ^ 6/2),然后你的函数平均每次调用超过2次(p = .5)。
此外,几何分布的方差为1-p / p ^ 2,因此即使在300亿个条目中,一个标准差也只是sqrt(2)。因此,我预计〜99%的时间循环将花费2 + 2 * sqrt(2)交互或~5次迭代。换句话说,我不会太担心它。
答案 1 :(得分:4)
从学术立场来看,这似乎是一个有趣的计划。但是,如果你在时钟上,只需要随机和不同的字符串,我将使用Data :: GUID模块。
use strict;
use warnings;
use Data::GUID qw( guid_string );
my $guid = guid_string();
答案 2 :(得分:2)
摆脱递归很容易;将递归调用转换为do-while循环。例如,将您的功能分成两部分; “主要”和帮助者。 “main”只调用帮助程序并查询数据库以确保它是唯一的。假设generate_random_string2是帮助器,这是一个骨架:
do {
$string = generate_random_string2(6);
} while (database->quick_select(...));
至于在获取有效字符串之前限制迭代次数,那么只保存最后生成的字符串并始终构建新字符串作为其函数呢?
例如,当你开始时,你没有字符串,所以我们只说你的字符串是'a'。然后,下次构建字符串时,将获得最后构建的字符串('a')并对其应用转换,例如递增最后一个字符。这给你'b'。等等。最终你达到了你所关心的最高性格(比如'z'),此时你附加'a'来获得'za',然后重复。
现在没有数据库,只有一个持久值可用于生成下一个值。当然,如果你想要真正的随机字符串,你必须使算法更复杂,但基本原理是相同的:
答案 3 :(得分:1)
基于使用MySQL,我还有一个想法。
create table string (
string_id int(10) not null auto_increment,
string varchar(6) not null default '',
primary key(string_id)
);
insert into string set string='';
update string
set string = lpad( hex( last_insert_id() ), 6, uuid() )
where string_id = last_insert_id();
select string from string
where string_id = last_insert_id();
这为您提供了一个增量十六进制值,该值用非零垃圾填充。