web-dev-qa-db-ja.com

.NETの短い一意の識別子

.NETで一意の識別子が必要です(GUIDはこの場合には長すぎるため使用できません)。

here が使用されるアルゴリズムは良い候補だと思いますか、または他に何か提案がありますか?

69
Noel

これは良いもの- http://www.singular.co.nz/blog/archive/2007/12/20/shortguid-a-shorter-and-url-friendly-guid-in-c- sharp.aspx

また、こちら YouTubeのようなGUID

Base64を使用できます。

string base64Guid = Convert.ToBase64String(Guid.NewGuid().ToByteArray());

これにより、E1HKfn68Pkms5zsZsvKONw ==のような文字列が生成されます。 GUIDは常に128ビットであるため、最後に常に存在し、22文字の文字列を提供することがわかっている==を省略できます。これは、 YouTube。

71
Dor Cohen

Dor Cohenのアプローチと同様のアプローチを使用しますが、いくつかの特殊文字を削除します。

var uid = Regex.Replace(Convert.ToBase64String(Guid.NewGuid().ToByteArray()), "[/+=]", "");     

これは、英数字のみを出力します。 UIDの長さが常に同じであるとは限りません。サンプルの実行を次に示します。

vmKo0zws8k28fR4V4Hgmw 
TKbhS0G2V0KqtpHOU8e6Ug 
rfDi1RdO0aQHTosh9dVvw
3jhCD75fUWjQek8XRmMg 
CQUg1lXIXkWG8KDFy7z6Ow 
bvyxW5aj10OmKA5KMhppw
pIMK8eq5kyvLK67xtsIDg
VX4oljGWpkSQGR2OvGoOQ 
NOHBjUUHv06yIc7EvotRg
iMniAuUG9kiGLwBtBQByfg
26
Jaime

シンプルで使いやすいパッケージ。一時的なリクエストIDジェネレーターに使用します。

https://www.nuget.org/packages/shortid

https://github.com/bolorundurowb/shortid

System.Randomを使用します

string id = ShortId.Generate();
// id = KXTR_VzGVUoOY

(githubページから)

数値、特殊文字、長さを指定することで生成されるidのタイプを制御する場合は、Generateメソッドを呼び出して、3つのパラメーターを渡します。1つ目は数値が必要かどうかを示すブール値、2つ目は特殊文字、最後の長さは好みの長さを示します。

string id = ShortId.Generate(true, false, 12);
// id = VvoCDPazES_w
14
BozoJoe
var ticks = new DateTime(2016,1,1).Ticks;
var ans = DateTime.Now.Ticks - ticks;
var uniqueId = ans.ToString("x");

これらのIDの生成を開始するベースライン日付(この場合は2016年1月1日)を保持します。これにより、IDが小さくなります。

生成された番号:af3c14996e54

13
adeel41

私の知る限り、 GUIDは一意であるとは限りません)の一部を除去するだけです -実際、一意であるとは程遠いです。

私が知っている最短のグローバルな一意性を保証することは、 このブログ投稿Jeff Atwood で紹介されています。リンクされた投稿では、GUIDを短縮する複数の方法について説明し、最終的に Ascii85 encoding を使用して20バイトに短縮します。

ただし、15バイト以下のソリューションが絶対に必要な場合は、グローバルに一意であることが保証されていないものを使用する以外に選択肢がないと思います。

8

私のローカルアプリでは、この時間ベースのアプローチを使用しています。

/// <summary>
/// Returns all ticks, milliseconds or seconds since 1970.
/// 
/// 1 tick = 100 nanoseconds
/// 
/// Samples:
/// 
/// Return unit     value decimal           length      value hex       length
/// --------------------------------------------------------------------------
/// ticks           14094017407993061       17          3212786FA068F0  14
/// milliseconds    1409397614940           13          148271D0BC5     11
/// seconds         1409397492              10          5401D2AE        8
///
/// </summary>
public static string TickIdGet(bool getSecondsNotTicks, bool getMillisecondsNotTicks, bool getHexValue)
{
    string id = string.Empty;

    DateTime historicalDate = new DateTime(1970, 1, 1, 0, 0, 0);

    if (getSecondsNotTicks || getMillisecondsNotTicks)
    {
        TimeSpan spanTillNow = DateTime.UtcNow.Subtract(historicalDate);

        if (getSecondsNotTicks)
            id = String.Format("{0:0}", spanTillNow.TotalSeconds);
        else
            id = String.Format("{0:0}", spanTillNow.TotalMilliseconds);
    }
    else
    {
        long ticksTillNow = DateTime.UtcNow.Ticks - historicalDate.Ticks;
        id = ticksTillNow.ToString();
    }

    if (getHexValue)
        id = long.Parse(id).ToString("X");

    return id;
}
6
Pollitzer

IDENTITY値はデータベース内で一意である必要がありますが、制限に注意する必要があります。たとえば、大量のレコードを操作している場合、大量のデータの挿入が基本的に不可能になります。

日付/時刻の値を使用することもできます。日付/時刻をPKとして使用するデータベースをいくつか見てきましたが、あまりきれいではありませんが、動作します。挿入を制御すると、コード内で値が一意になることを効果的に保証できます。

6
David

アプリに少数のMILLIION人がいない場合、同じMILLISECONDで短い一意の文字列を生成することを使用して、以下の関数の使用を検討できます。

private static readonly Object obj = new Object();
private static readonly Random random = new Random();
private string CreateShortUniqueString()
{
    string strDate = DateTime.Now.ToString("yyyyMMddhhmmssfff");
    string randomString ;
    lock (obj)
    {
        randomString = RandomString(3);
    }
    return strDate + randomString; // 16 charater
}
private string RandomString(int length)
{

    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy";
    var random = new Random();
    return new string(Enumerable.Repeat(chars, length)
      .Select(s => s[random.Next(s.Length)]).ToArray());
}

次の99年でアプリを使用する必要がある場合は、yyyyをyyに変更します。
20160511の更新:ランダム関数を修正
-ロックオブジェクトの追加
-RandomString関数からランダム変数を移動する
参照

3
Chinh Phan

ここで私のソリューションは、同時実行に対して安全ではなく、1秒あたり1000 GUID以下であり、スレッドセーフです。

public static class Extensors
{

    private static object _lockGuidObject;

    public static string GetGuid()
    {

        if (_lockGuidObject == null)
            _lockGuidObject = new object();


        lock (_lockGuidObject)
        {

            Thread.Sleep(1);
            var Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            var epochLong = Convert.ToInt64((DateTime.UtcNow - Epoch).TotalMilliseconds);

            return epochLong.DecimalToArbitrarySystem(36);

        }

    }

    /// <summary>
    /// Converts the given decimal number to the numeral system with the
    /// specified radix (in the range [2, 36]).
    /// </summary>
    /// <param name="decimalNumber">The number to convert.</param>
    /// <param name="radix">The radix of the destination numeral system (in the range [2, 36]).</param>
    /// <returns></returns>
    public static string DecimalToArbitrarySystem(this long decimalNumber, int radix)
    {
        const int BitsInLong = 64;
        const string Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

        if (radix < 2 || radix > Digits.Length)
            throw new ArgumentException("The radix must be >= 2 and <= " + Digits.Length.ToString());

        if (decimalNumber == 0)
            return "0";

        int index = BitsInLong - 1;
        long currentNumber = Math.Abs(decimalNumber);
        char[] charArray = new char[BitsInLong];

        while (currentNumber != 0)
        {
            int remainder = (int)(currentNumber % radix);
            charArray[index--] = Digits[remainder];
            currentNumber = currentNumber / radix;
        }

        string result = new String(charArray, index + 1, BitsInLong - index - 1);
        if (decimalNumber < 0)
        {
            result = "-" + result;
        }

        return result;
    }

最適化されていないコード、サンプルのみ!.

2
ur3an0

私はそれが投稿日からかなり遠いことを知っています... :)

9個の16進文字のみを生成するジェネレーターがあります。例:C9D6F7FF3、C9D6FB52C

public class SlimHexIdGenerator : IIdGenerator
{
    private readonly DateTime _baseDate = new DateTime(2016, 1, 1);
    private readonly IDictionary<long, IList<long>> _cache = new Dictionary<long, IList<long>>();

    public string NewId()
    {
        var now = DateTime.Now.ToString("HHmmssfff");
        var daysDiff = (DateTime.Today - _baseDate).Days;
        var current = long.Parse(string.Format("{0}{1}", daysDiff, now));
        return IdGeneratorHelper.NewId(_cache, current);
    }
}


static class IdGeneratorHelper
{
    public static string NewId(IDictionary<long, IList<long>> cache, long current)
    {
        if (cache.Any() && cache.Keys.Max() < current)
        {
            cache.Clear();
        }

        if (!cache.Any())
        {
            cache.Add(current, new List<long>());
        }

        string secondPart;
        if (cache[current].Any())
        {
            var maxValue = cache[current].Max();
            cache[current].Add(maxValue + 1);
            secondPart = maxValue.ToString(CultureInfo.InvariantCulture);
        }
        else
        {
            cache[current].Add(0);
            secondPart = string.Empty;
        }

        var nextValueFormatted = string.Format("{0}{1}", current, secondPart);
        return UInt64.Parse(nextValueFormatted).ToString("X");
    }
}
1
hazjack

@dorcohenの回答と@pootzkoのコメントに基づきます。これを使用できます。ワイヤ上で安全です。

var errorId = System.Web.HttpServerUtility.UrlTokenEncode(Guid.NewGuid().ToByteArray());
1
Ahuman

以下を使用して、一意のGUID(35文字)を作成します。

// Example: 7b08e3d-186b-46f0-99c8-e8252033715d
var strUniqueGuid = Guid.NewGuid().ToString();

16文字の一意のGUIDが必要な場合は、以下のコードを使用してください

// Example: 7b08e3d-186b-46f
var strUniqueGuid = Guid.NewGuid().ToString();
strUniqueGuid=strUniqueGuid.Substring(0, 16);
0
Binny

文字列を入力する必要がない場合は、次を使用できます。

static class GuidConverter
{
    public static string GuidToString(Guid g)
    {
        var bytes = g.ToByteArray();
        var sb = new StringBuilder();
        for (var j = 0; j < bytes.Length; j++)
        {
            var c = BitConverter.ToChar(bytes, j);
            sb.Append(c);
            j++;
        }
        return sb.ToString();
    }

    public static Guid StringToGuid(string s) 
        => new Guid(s.SelectMany(BitConverter.GetBytes).ToArray());
}

これにより、Guidは次のような8文字の文字列に変換されます。

{b77a49a5-182b-42fa-83a9-824ebd6ab58d}-> "䦥띺ᠫ䋺ꦃ亂檽趵"

{c5f8f7f5-8a7c-4511-b667-8ad36b446617}-> "엸詼䔑架펊䑫ᝦ"

0
Whopperle