2009-08-14 7 views
6

내 사용자에게 Twitter에서 사용할 수있는 더 짧은 대체 URL을 제공하기 위해 응용 프로그램에 URL 단축 기능을 구현하고 있습니다. 요점은이 동일한 서비스를 제공하는 단축 서비스와 독립적이며 내 웹 앱의 기능으로 포함시키는 것입니다.C#에서 고유 한 임의의 문자 시퀀스를 만들려면 어떻게해야합니까?

약 6 자의 고유 한 임의 문자 시퀀스를 만드는 가장 좋은 방법은 무엇입니까? 나는 대체 URL을 가질 데이터베이스의 항목에 대한 색인으로이를 사용할 계획입니다.

편집 :

이 기능을 사용하면 모든 새 작업 광고가 사용자 정의 제목과 URL을 더한 짧은 트위터에 사용될를 얻을 것이다 작업 보드 웹 사이트에 사용됩니다. 즉, 고유 한 6 자 조합의 총 수는 오랜 시간 동안 충분할 것입니다.

답변

3

'랜덤'이 정말로 필요한가요? '고유 한'것이 충분합니까?

고유는 매우 간단합니다. URL을 데이터베이스에 삽입하고 해당 레코드의 순차적 ID를 선택한 문자 집합으로 표시되는 기본 n 숫자로 변환하면됩니다.

예를 들어, 시퀀스에서 [A-Z] 만 사용하려면 레코드의 ID를 A = 1, B = 2, ... Z = 26 인 기본 26 숫자로 변환합니다. algothithm은 재귀 적 div26/mod26이며, 여기서 몫은 필수 문자이고 나머지는 다음 문자를 계산하는 데 사용됩니다.

그런 다음 URL을 검색 할 때베이스 26 숫자를 10 진수로 다시 변환하는 역함수를 수행합니다. SELECT URL WHERE ID = decimal을 수행하면 작업이 완료됩니다!

편집 : 리드 Copsey의 대답의 아이디어에 따라

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'인가? ** –

+0

@Maxim - 1 년 전에 기억하기 힘들었지 만, 나는 그것이 인코딩 단어의 길이라고 상상할 것이다. 즉 위의 기본 26 인코딩의 경우 26이됩니다. 그러나 코드에 버그가 있다고 생각합니다. 실제로 1보다 커야합니다. –

3

고유 한 시퀀스를 만드는 가장 간단한 방법은 다음과 같이 순차적으로 수행하는 것입니다. aaaaaa aaaaab aaaaac ... 이것은 반드시 가장 좋은 것은 아니지만 첫 번째 12230590463 시퀀스의 고유성을 보장합니다 (az 및 AZ를 as 고유 한 문자). 그것보다 더 많은 URL이 필요하다면 일곱 번째 문자를 추가해야합니다.

그들은 임의의 순서는 아니지만. 무작위로 만들면 48 번, 6 번 무작위로 선택하십시오. 하지만 충돌이 발생할 확률이 높으므로 기존 DB에서 "used"시퀀스를 확인해야합니다.

+0

더 많은 작업이 필요하며 더 많은 값을 사용하면 결국 시간 초과가 발생할 수 있습니다. – RiddlerDev

+0

예. 순차는 모든 것을 피하지만 순차 값으로 끝납니다 (괜찮을 수도 있고 그렇지 않을 수도 있습니다). 트위터 URL의 경우 seq를 사용합니다. 값은 참으로 "무작위"가되는 것이 중요하지 않으므로 죽은 단순한 생성을 사용하여 큰 값의 고유 한 값을 가질 수 있습니다. –

+0

0-9를 문자 집합의 일부로 포함하면 56800235584 개의 고유 값 (~ 4.6x az, az)이 있어야합니다. 나는 그가 "문자"를 언급했음을 알지만 숫자는 숫자를 포함 할 수 있습니다. * $ %() 등과 같은 다른 문자도 포함 시키면 조금 더 부풀려 질 것입니다 (원래 세트보다 적어도 9 배 이상). –

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이 고유하다는 것을 보장하기 위해 데이터베이스 자동 번호를 사용할 수 있으며 DB 또는 비즈니스 계층의 sproc에서 URL을 계산할 수 있습니다 ?

또한 값이 비싸고 DB가 가변 길이 임의 문자열과 달리 기본 및 외래 키로 사용 및 해싱되도록 최적화되어 있습니다.

1

랜덤 생성기의 유용성은 사용자가 임의의 URL을 연결하여 링크가 없어야하는 것을 찾지 못하도록 제한하는 것입니다. 이것이 목표가 아니라면 순차적 ID는 잘 작동합니다. "유아"기술을 사용하고 있다는 인상을주고 싶지 않다면 (직업 광고가 # 000001임을 알았을 때) 임의의 값으로 시퀀스를 시작하는 것이 어떻습니까?

0

가능한 모든 값의 테이블을 유지하는 대신 사용했던 값의 테이블을 유지하십시오. random 함수를 사용하여 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

당신은 상태 당신이 당신의 계산에 birthday paradox을 고려했다 무작위로 생성을위한 "고유의 6 개 문자의 조합 총 수는 시간이 오래에 대해 충분하게 될 것"? 이것은 일반적으로 예상되는 범위보다 1 차 이하의 범위 내에서 임의의 ID를 생성하려는 시도의 일반적입니다.

정말로 임의의 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; 
} 
관련 문제