C# 创建唯一的5个字符的字母数字字符串

C# 创建唯一的5个字符的字母数字字符串,c#,string,alphanumeric,promotion-code,C#,String,Alphanumeric,Promotion Code,我们正在考虑创建发送给客户的促销代码,我们被告知发送的每个代码必须是唯一的-5个字符-字母数字 我曾想过对串联字符串进行散列,并获取散列的前5个字符,但很有可能同样的5个字符会一次又一次出现 有谁能给我一些关于创建这个每次都是唯一的5个字符的字母数字字符串的建议吗?我不久前提出了这个,它可能会满足您的需要 /// <summary> /// Return a string of random hexadecimal values which is 6 characters long

我们正在考虑创建发送给客户的促销代码,我们被告知发送的每个代码必须是唯一的-5个字符-字母数字

我曾想过对串联字符串进行散列,并获取散列的前5个字符,但很有可能同样的5个字符会一次又一次出现


有谁能给我一些关于创建这个每次都是唯一的5个字符的字母数字字符串的建议吗?

我不久前提出了这个,它可能会满足您的需要

/// <summary>
/// Return a string of random hexadecimal values which is 6 characters long and relatively unique.
/// </summary>
/// <returns></returns>
/// <remarks>In testing, result was unique for at least 10,000,000 values obtained in a loop.</remarks>
public static string GetShortID()
{
    var crypto = new System.Security.Cryptography.RNGCryptoServiceProvider();
    var bytes = new byte[5];
    crypto.GetBytes(bytes); // get an array of random bytes.      
    return BitConverter.ToString(bytes).Replace("-", string.Empty); // convert array to hex values.
}
我将创建一个包含所有可能的5位字符串的表(PromoCode)。然后创建另一个带有两个字段的表代码:

Code varchar(5), CampaignId uniqueidentifier
通过这种方式,您可以跟踪每个活动中使用的产品。要获取随机未使用的促销代码,请使用以下语句:

select top 1 Code 
from PromoCode pc
    left join CampaignPromoCode cpc on cpc.Code = pc.Code
where cpc.CampaignId = 'campaign-id-goes-here'
  and cpc.Code is null
order by newid()

这里的底线是,您可能应该回到管理层,告诉他们强制100%绝对唯一性的要求是一个成本非常高的要求,并且您可以用成本的一小部分获得99.9999%的唯一性。然后使用roryap的代码生成一个随机的、主要是唯一的代码。

正如我在另一个答案的评论中提到的,它可能不足以满足您的目的。我又编了一些代码,生成了一个随机字母数字字符字符串。这一次,它们不限于0-9和A-F——即随机生成的十六进制等价物。相反,它们由全范围的字母数字字符组成,至少是大写字母。考虑到我们将从16个可能的十六进制字符增加到36个可能的完整字母表字符和0-9,这将充分增加唯一性的可能性

尽管如此,当我尝试超过10000000次时,仍有大量重复。这正是野兽的本性:使用如此短的字符串获得DUP的可能性相当高。无论如何,它在这里。你可以玩玩它。如果你的客户不介意小写字母——例如,如果“RORYAP”与“RORYAP”不同——那么这将进一步增加唯一性的可能性

/// <summary>
/// Instances of this class are used to geneate alpha-numeric strings.
/// </summary>
public sealed class AlphaNumericStringGenerator
{
    /// <summary>
    /// The synchronization lock.
    /// </summary>
    private object _lock = new object();

    /// <summary>
    /// The cryptographically-strong random number generator.
    /// </summary>
    private RNGCryptoServiceProvider _crypto = new RNGCryptoServiceProvider();

    /// <summary>
    /// Construct a new instance of this class.
    /// </summary>
    public AlphaNumericStringGenerator()
    {
        //Nothing to do here.
    }

    /// <summary>
    /// Return a string of the provided length comprised of only uppercase alpha-numeric characters each of which are
    /// selected randomly.
    /// </summary>
    /// <param name="ofLength">The length of the string which will be returned.</param>
    /// <returns>Return a string of the provided length comprised of only uppercase alpha-numeric characters each of which are
    /// selected randomly.</returns>
    public string GetRandomUppercaseAlphaNumericValue(int ofLength)
    {
        lock (_lock)
        {
            var builder = new StringBuilder();

            for (int i = 1; i <= ofLength; i++)
            {
                builder.Append(GetRandomUppercaseAphanumericCharacter());
            }

            return builder.ToString();
        }
    }

    /// <summary>
    /// Return a randomly-generated uppercase alpha-numeric character (A-Z or 0-9).
    /// </summary>
    /// <returns>Return a randomly-generated uppercase alpha-numeric character (A-Z or 0-9).</returns>
    private char GetRandomUppercaseAphanumericCharacter()
    {
            var possibleAlphaNumericValues =
                new char[]{'A','B','C','D','E','F','G','H','I','J','K','L',
                'M','N','O','P','Q','R','S','T','U','V','W','X','Y',
                'Z','0','1','2','3','4','5','6','7','8','9'};

            return possibleAlphaNumericValues[GetRandomInteger(0, possibleAlphaNumericValues.Length - 1)];
    }

    /// <summary>
    /// Return a random integer between a lower bound and an upper bound.
    /// </summary>
    /// <param name="lowerBound">The lower-bound of the random integer that will be returned.</param>
    /// <param name="upperBound">The upper-bound of the random integer that will be returned.</param>
    /// <returns> Return a random integer between a lower bound and an upper bound.</returns>
    private int GetRandomInteger(int lowerBound, int upperBound)
    {
        uint scale = uint.MaxValue;

        // we never want the value to exceed the maximum for a uint, 
        // so loop this until something less than max is found.
        while (scale == uint.MaxValue)
        {
            byte[] fourBytes = new byte[4];
            _crypto.GetBytes(fourBytes); // Get four random bytes.
            scale = BitConverter.ToUInt32(fourBytes, 0); // Convert that into an uint.
        }

        var scaledPercentageOfMax = (scale / (double) uint.MaxValue); // get a value which is the percentage value where scale lies between a uint's min (0) and max value.
        var range = upperBound - lowerBound;
        var scaledRange = range * scaledPercentageOfMax; // scale the range based on the percentage value
        return (int) (lowerBound + scaledRange);
    }
}
//
///此类的实例用于生成字母数字字符串。
/// 
公共密封类字母数字字符串生成器
{
/// 
///同步锁。
/// 
私有对象_lock=新对象();
/// 
///加密强随机数生成器。
/// 
私有RNGCryptoServiceProvider _crypto=新的RNGCryptoServiceProvider();
/// 
///构造该类的新实例。
/// 
公共字母数字字符串生成器()
{
//这里没什么可做的。
}
/// 
///返回所提供长度的字符串,该字符串仅由大写字母数字字符组成,每个字母数字字符
///随机抽取。
/// 
///将返回的字符串的长度。
///返回所提供长度的字符串,该字符串仅由大写字母数字字符组成,每个字母数字字符
///随机抽取。
公共字符串GetRandomUppercaseAlphaNumericValue(长度的整数)
{
锁
{
var builder=新的StringBuilder();

对于(int i=1;我创建了一个文本文件,并在创建时将每个代码附加到该文件中,然后每次创建一个文本文件时,都会不断生成它们,直到它是唯一的一个不在该文件中。您必须将现有的文件存储在某个位置,并将每个创建的文件与所有文件进行比较。此外,在开始创建之前,请确保您的问题确实有一个解决方案。如果可以,请与我们联系e 26个字符+10个数字(已经有问题了,因为人们可能会抱怨1和i容易混淆,0和o等等)这仍然会给您留下不超过36^5=60 466 176个代码。这足够吗?所有时间?一个月?一周?有多少商店、客户、操作?何时回收代码?如何回收?@Richard.Gale:是否可以生成一个序列值列表,例如1000000个,存储在表中,然后让系统随机选择一个并将其标记为“已使用”?下一个查询将仅限于未使用的查询,并获得一个新的随机数,等等@Cᴏʀ为什么是随机的?为什么不只是迭代?谢谢@roryap。我正在寻找一种基于代码的解决方案,它不涉及大量循环和/或数据库调用。但是,是的,我需要能够保证每次都是唯一的,否则这个练习就太难了pointless@Richard.Gale这不涉及循环或数据库调用。这只是为了测试。这很重要e本身。它就像一个“短guid”。它是随机的,但不保证唯一性…有可能,但不太可能,有一个重复的。@roryap你甚至自己说过:“5个字符并不是唯一的”@Scottie——正如我所说,我对长度6测试了1000万次,结果是唯一的。我忘了5的结果是什么。唯一性都是相对的。即使是GUID也不是真正唯一的。2个同时访问该表的独立用户,仍然可以返回相同的代码。是的,但您可以将方法作为一个单例编写,以便@Richard.Gale:可以防止并发访问。更大的问题是,此表需要在超过60000000条记录的情况下运行良好。为了防止并发问题,您可以使用单例模式,或者创建一个存储过程来锁定表,获取下一个代码,并将其返回给您。这是一个很好的例子乐:。促销代码表不必那么大,基本上你可以减少它,因为我真的怀疑任何活动是否会使用所有2176782336代码。
/// <summary>
/// Instances of this class are used to geneate alpha-numeric strings.
/// </summary>
public sealed class AlphaNumericStringGenerator
{
    /// <summary>
    /// The synchronization lock.
    /// </summary>
    private object _lock = new object();

    /// <summary>
    /// The cryptographically-strong random number generator.
    /// </summary>
    private RNGCryptoServiceProvider _crypto = new RNGCryptoServiceProvider();

    /// <summary>
    /// Construct a new instance of this class.
    /// </summary>
    public AlphaNumericStringGenerator()
    {
        //Nothing to do here.
    }

    /// <summary>
    /// Return a string of the provided length comprised of only uppercase alpha-numeric characters each of which are
    /// selected randomly.
    /// </summary>
    /// <param name="ofLength">The length of the string which will be returned.</param>
    /// <returns>Return a string of the provided length comprised of only uppercase alpha-numeric characters each of which are
    /// selected randomly.</returns>
    public string GetRandomUppercaseAlphaNumericValue(int ofLength)
    {
        lock (_lock)
        {
            var builder = new StringBuilder();

            for (int i = 1; i <= ofLength; i++)
            {
                builder.Append(GetRandomUppercaseAphanumericCharacter());
            }

            return builder.ToString();
        }
    }

    /// <summary>
    /// Return a randomly-generated uppercase alpha-numeric character (A-Z or 0-9).
    /// </summary>
    /// <returns>Return a randomly-generated uppercase alpha-numeric character (A-Z or 0-9).</returns>
    private char GetRandomUppercaseAphanumericCharacter()
    {
            var possibleAlphaNumericValues =
                new char[]{'A','B','C','D','E','F','G','H','I','J','K','L',
                'M','N','O','P','Q','R','S','T','U','V','W','X','Y',
                'Z','0','1','2','3','4','5','6','7','8','9'};

            return possibleAlphaNumericValues[GetRandomInteger(0, possibleAlphaNumericValues.Length - 1)];
    }

    /// <summary>
    /// Return a random integer between a lower bound and an upper bound.
    /// </summary>
    /// <param name="lowerBound">The lower-bound of the random integer that will be returned.</param>
    /// <param name="upperBound">The upper-bound of the random integer that will be returned.</param>
    /// <returns> Return a random integer between a lower bound and an upper bound.</returns>
    private int GetRandomInteger(int lowerBound, int upperBound)
    {
        uint scale = uint.MaxValue;

        // we never want the value to exceed the maximum for a uint, 
        // so loop this until something less than max is found.
        while (scale == uint.MaxValue)
        {
            byte[] fourBytes = new byte[4];
            _crypto.GetBytes(fourBytes); // Get four random bytes.
            scale = BitConverter.ToUInt32(fourBytes, 0); // Convert that into an uint.
        }

        var scaledPercentageOfMax = (scale / (double) uint.MaxValue); // get a value which is the percentage value where scale lies between a uint's min (0) and max value.
        var range = upperBound - lowerBound;
        var scaledRange = range * scaledPercentageOfMax; // scale the range based on the percentage value
        return (int) (lowerBound + scaledRange);
    }
}