2009-08-14 35 views
6

我在我的應用程序中實現了URL縮短功能,以便爲我的用戶提供可在Twitter中使用的更短的替代URL。重點是獨立於提供相同服務的縮短服務,並將其作爲我的Web應用程序的一項功能。如何在C#中創建獨特的隨機字符序列?

什麼是創建約6個字符的獨特隨機序列字符的最佳方式是什麼?我計劃使用它作爲我的數據庫中的項目的索引,這些項目將具有其他URL。

編輯:

此功能將在就業局的網站,在那裏每一個新的招聘廣告將獲得與標題自定義URL加上較短的一個在Twitter上使用使用。也就是說,獨特的6個字符組合的總數將會長時間綽綽有餘。

回答

3

你真的需要「隨機」,或將「獨一無二」就足夠了?

獨特之處是非常簡單 - 只需將URL到數據庫中,並轉換順序編號爲記錄是由您選擇的字符集爲代表的鹼基-n個。例如,如果您只想在序列中使用[A-Z],則將記錄的id轉換爲基數爲26的數字,其中A = 1,B = 2,... Z = 26。 algothithm是一個遞歸的div26/mod26,其中商是必需的字符,餘數用於計算下一個字符。

然後檢索URL時,您執行的反函數,這是基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; 
} 
+0

感謝您的回答!我有一個問題:**什麼是'encodingBase'?** – 2010-11-26 18:01:40

+0

@Maxim - 一年前很難記住,但我會想象它是編碼字的長度;即對於像上面那樣的base-26編碼,那麼它將是26.然而,我認爲在代碼中也存在一個錯誤!它應該是> 1 – 2010-11-28 10:30:56

3

製作獨特序列的最簡單方法是按順序執行此操作,即:aaaaaa aaaaab aaaaac ...這些不一定是最漂亮的,但會保證第一個12230590463序列的唯一性(假設您使用az和AZ作爲獨特的人物)。如果你需要更多的URL,你需要添加第七個字符。

雖然它們不是隨機序列。如果你製作的是隨機的,只需選擇48個隨機字符,6次。但是,您需要檢查現有的數據庫是否存在「已使用」序列,因爲您將更有可能發生衝突。

+0

它確實會導致更多的工作,並可能超時您最終使用的值越多。 – RiddlerDev 2009-08-14 01:09:23

+0

是的。 Sequential可以避免所有這些,但是最終會產生連續的值(可能會也可能不會很好)。對於Twitter網址,我只是使用seq。值,因爲它確實無關緊要,它們真的是「隨機的」,並且你將擁有一個巨大的唯一值序列,具有簡單的代碼 – 2009-08-14 16:32:16

+0

如果包含0-9作爲字符集的一部分,那麼你有56800235584獨特的值(〜4.6x只是AZ,AZ)。我知道他剛纔提到「角色」,但可能包括數字。如果你還加入了一些其他的字符,如* $%()等,那麼它也會增加一些(至少是原來的9倍)。 – 2009-08-14 17:26:07

0

想想這更多這裏是一個想法。

您可以從一個關鍵表開始,遞增字符AAAAAA - ZZZZZZ。

然後在每次插入新URL時從該表中隨機選擇,並從可用密鑰中刪除。

想法?

對於隨機選擇嘗試這種link

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 
2

我會使用自動編號系統,並創建一個算法來生成密鑰。即1 = a,2 = b,27 = aa等。

您可以使用數據庫自​​動編號來確保您的URL是唯一的,並且可以計算可能位於數據庫或業務層中的存儲區中的URL ?

此外,您現在可以索引增量數字,這是便宜的和數據庫的優化,這些將被使用和哈希作爲主/外鍵,而不是一個可變長度的隨機字符串。

1

隨機生成器的有用性限於防止用戶插入隨機URL以找到他們不應該鏈接的東西。如果這不是你的目標,那麼順序ID應該可以正常工作。如果你不想讓用戶覺得他們使用的是「幼兒」技術(當他們看到他們的招聘廣告是#000001),爲什麼不以某種任意價值開始序列呢?

0

而不是保留一個所有可能的值的表,只是保留一個你已經使用的值的表。使用隨機函數生成6個隨機值,1到26,從中產生字符串並將其保存在數組或表中。如果它已經存在,您可以(a)生成另一個字符串,或者(b)在表格中移動到下一個可用(缺少)的6字母字符串並使用該值。 (b)在表格填滿時將更有效率。

0

繼裏德·科普塞的答案的想法,我提出以下代碼:

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的方法,但應該工作。

1

當你說出「獨特的6個字符組合總數將綽綽有餘了好久」爲您隨機生成你的因素進入birthday paradox你的計算?這通常是任何嘗試在範圍內創建隨機ID的禍根,該範圍只有一個數量級或更少,然後纔是需要的預期範圍。

要創建真正的隨機編號,你需要創建生成新的隨機值,檢查是否該值已被使用,然後如果需要的話重複這個循環的循環。生日悖論意味着您很快就會達到許多生成的值已被使用的程度(儘管只佔總範圍的一小部分),這會導致程序隨着時間的推移變得越來越慢,直到它花費數千嘗試(和數據庫查找)來生成每個ID。

我建議你去編碼順序ID的想法。爲了避免用戶能夠簡單地增加/減少URL中的值以「探索」,您可以使用組合位移和替代的有序字母列表(而不是1 = a,2 = b使用1 = t,2 = j等)。

0

我用它做了非常相似的事情。我不會擔心它的速度,因爲它將是一個很少使用的事件和表格。但是可以根據需要增加字符串。

/// 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; 
}