[英]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.