[英]How can I create an unique random sequence of characters in C#?
我正在我的应用程序中实现URL缩短功能,以便为我的用户提供可在Twitter中使用的更短的替代URL。 重点是独立于提供相同服务的缩短服务,并将其作为我的网络应用程序的一项功能。
创建一个大约6个字符的独特随机字符序列的最佳方法是什么? 我计划将其用作我的数据库中具有备用URL的项目的索引。
编辑:
此功能将用于工作板网站,其中每个新的工作广告都将获得带有标题的自定义URL以及要在Twitter中使用的较短的URL。 也就是说,长期以来,独特的6个字符组合的总数将绰绰有余。
制作独特序列的最简单方法是按顺序执行此操作,即:aaaaaa aaaaab aaaaac ...这些不一定是最漂亮的,但会保证第一个12230590463序列的唯一性(假设您使用az和AZ作为唯一字符)。 如果您需要更多的URL,则需要添加第七个字符。
但它们不是随机序列。 如果你做随机的,只需选择48次,6次随机字符。 但是,您需要检查现有数据库中的“已使用”序列,因为您更有可能发生冲突。
你真的需要'随机',还是'独特'就足够了?
Unique非常简单 - 只需将URL插入数据库,然后将该记录的顺序ID转换为base-n数字,该数字由您选择的characterset表示。
例如,如果您只想在序列中使用[AZ],则将记录的id转换为基数为26的数字,其中A = 1,B = 2,... Z = 26。 algothithm是递归div26 / mod26,其中商是必需字符,余数用于计算下一个字符。
然后在检索URL时,执行反函数,即将base-26数转换回十进制数。 执行SELECT URL WHERE ID = decimal,你就完成了!
编辑:
private string alphabet = "abcdefghijklmnopqrstuvwxyz";
// or whatever you want. Include more characters
// for more combinations and shorter URLs
public string Encode(int databaseId)
{
string encodedValue = String.Empty;
while (databaseId > encodingBase)
{
int remainder;
encodedValue += alphabet[Math.DivRem(databaseId, alphabet.Length,
out remainder)-1].ToString();
databaseId = remainder;
}
return encodedValue;
}
public int Decode(string code)
{
int returnValue;
for (int thisPosition = 0; thisPosition < code.Length; thisPosition++)
{
char thisCharacter = code[thisPosition];
returnValue += alphabet.IndexOf(thisCharacter) *
Math.Pow(alphabet.Length, code.Length - thisPosition - 1);
}
return returnValue;
}
我会使用自动编号系统,并创建一个算法来生成密钥。 即1 = a,2 = b,27 = aa等
您可以使用数据库自动编号来保证您的URL是唯一的,并且您可以在数据库或业务层的sproc中计算URL?
此外,您现在可以索引递增数字,该数字便宜,并且DB优化用于这些数字并且作为主键/外键进行散列,而不是可变长度随机字符串。
随机生成器的用处仅限于阻止用户插入随机URL以查找他们不应该链接的内容。 如果这不是您的目标,那么顺序ID应该可以正常工作。 如果您只是不想让用户觉得他们正在使用“婴儿”技术(当他们看到他们的工作广告是#000001时),为什么不以某个任意值启动序列呢?
当你指出“随机生成的长期独特的6个字符组合的总数将足够多 ”时,您是否将生日悖论计算在计算中? 这通常是在一个范围内创建随机ID的任何尝试的祸根,该范围仅为所需的预期范围的1个数量级或更少。
要创建真正的随机ID,您需要创建一个生成新随机值的循环,检查是否已使用该值,然后根据需要重复循环。 生日悖论意味着您很快就会到达生成的许多值已经被使用的点(尽管只消耗了总量程的一小部分),这会导致程序随着时间的推移变得越来越慢,直到数千万尝试(和数据库查找)生成每个ID。
我建议你采用编码顺序ID的想法。 为了避免用户能够简单地将URL中的值递增/递减为“探索”的问题,您可以使用组合位移和备用的有序字母列表(而不是1 = a,2 = b使用1 = t,2 = j等)。
在这里考虑更多是一个想法。
您可以从密钥表开始,递增字符AAAAAA - ZZZZZZ。
然后在每次插入新URL时从该表中随机选择,并从可用键中删除。
思考?
对于随机选择尝试此链接
Select a random row with MySQL:
SELECT column FROM table
ORDER BY RAND()
LIMIT 1
Select a random row with PostgreSQL:
SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1
Select a random row with Microsoft SQL Server:
SELECT TOP 1 column FROM table
ORDER BY NEWID()
Select a random row with IBM DB2
SELECT column, RAND() as IDX
FROM table
ORDER BY IDX FETCH FIRST 1 ROWS ONLY
Thanks Tim
Select a random record with Oracle:
SELECT column FROM
( SELECT column FROM table
ORDER BY dbms_random.value )
WHERE rownum = 1
不要保留所有可能值的表,只需保留一个您使用过的值的表。 使用随机函数生成6个随机值,1到26,从中生成字符串并将其保存在数组或表中。 如果它已经存在,您可以(a)生成另一个字符串,或(b)通过表移动到下一个可用(缺失)的6个字母的字符串并使用该值。 (b)当桌子填满时会更有效率。
根据Reed Copsey的回答,我提出以下代码:
class IDGetter
{
private StringID ID = new StringID();
public string GetCurrentID()
{
string retStr = "";
if (ID.char1 > 51)
id.char1 = 0;
if (ID.char2 > 51)
id.char2 = 0;
if (ID.char3 > 51)
id.char3 = 0;
if (ID.char4 > 51)
id.char4 = 0;
if (ID.char5 > 51)
id.char5 = 0;
if (ID.char6 > 51)
throw new Exception("the maximum number of id's has been reached");
return ToIDChar(ID.char1) + ToIDChar(ID.char2) + ToIDChar(ID.char3) + ToIDChar(ID.char4) + ToIDChar(ID.char5) + ToIDChar(ID.char6)
id.char1++;
}
public void SetCurrentID(StringID id) //for setting the current ID from storage or resetting it or something
{
this.ID = id;
}
private const string alphabet = "abcdefghijklmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static string ToIDChar(int number)
{
if (number > 51 || number < 0)
{
throw new InvalidArgumentException("the number passed in (" + number + ") must be between the range 0-51");
}
return alphabet[number];
}
}
public struct StringID
{
public int char1 = 0;
public int char2 = 0;
public int char3 = 0;
public int char4 = 0;
public int char5 = 0;
public int char6 = 0;
}
您可能想要提出一种存储当前ID的方法,但该方法应该可行。
我用它来做一些非常相似的事情。 我不担心它的速度,因为它将是一个很少使用的事件和表。 但是可以根据需要增加字符串。
/// Generates a string and checks for existance
/// <returns>Non-existant string as ID</returns>
public static string GetRandomNumbers(int numChars, string Type)
{
string result = string.Empty;
bool isUnique = false;
while (!isUnique)
{
//Build the string
result = MakeID(numChars);
//Check if unsued
isUnique = GetValueExists(result, Type);
}
return result;
}
/// Builds the string
public static string MakeID(int numChars)
{
string random = string.Empty;
string[] chars = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
Random rnd = new Random();
for (int i = 0; i < numChars; i++)
{
random += chars[rnd.Next(0, 35)];
}
return random;
}
/// Checks database tables based on type for existance, if exists then retry
/// <returns>true or false</returns>
private static bool GetValueExists(string value, string Type)
{
bool result = false;
string sql = "";
if (Type == "URL")
{
sql = string.Format(@"IF EXISTS (SELECT COUNT(1) FROM myTable WHERE uniqueString = '{0}')
BEGIN
SELECT 1
END
ELSE
BEGIN
SELECT 0
END ", value);
}
//query the DB to see if it's in use
result = //ExecuteSQL
return result;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.