创建一个独特的5个字符的字母数字字符串

时间:2016-04-14 14:16:02

标签: c# string alphanumeric promotion-code

我们正在寻找创建促销代码以发送给客户,我们被告知每个代码发送都是独一无二的 - 5个字符 - 字母数字。

我想做一个连接字符串的哈希并取哈希的前5个字符,但很有可能会一次又一次地出现相同的5个字符。

任何人都可以给我任何关于创建这个独特的5字符字母数字字符串的指示吗?

4 个答案:

答案 0 :(得分:4)

正如我在其他答案的评论中提到的,它可能不足以满足您的目的。我编写了一些代码,生成一串随机字母数字字符。这次,它们不限于0-9和A-F--即随机生成的nibbles的十六进制等值。相反,它们由全系列的字母数字字符组成,至少包含大写字母。这应该足以增加唯一性的可能性,因为我们从16个可能的字符到十六进制到36个可能的字符,带有完整的字母和0-9。

然而,当我跑了10,000,000次尝试时,有很多重复。它只是野兽的本质:你用这么短的字符串获得重复的可能性相当高。无论如何,这是它。你可以玩它。如果您的客户不介意小写字母 - 例如如果" 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);
    }
}

答案 1 :(得分:2)

我想了一会儿这可能是你正在寻找的东西。

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

我理解你的要求是它必须&#34;是唯一的,但请记住,唯一性充其量只是一个相对的概念。即使是我们的老朋友the GUID也不是真正的唯一:

  

......随机生成两次相同数字的概率   可以忽略不计

如果我没记错的话,我发现我的代码不是100%唯一的5个字符,经过多次,多次迭代(数十万甚至可能是数百万 - 我完全不记得),但是在使用6进行测试时,结果 对于在循环中获得的至少10,000,000个值是唯一的。

您可以自行测试5,并确定它是否足够独特。如果需要,只需将6切换为5

附录:其他一些人提醒我,您可能需要考虑线程安全。这是一种经过修改的方法:

private static object _lock = new object();

/// <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()
{
    lock(_lock)
    {
        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.
    }
}

答案 2 :(得分:0)

我会创建一个包含所有可能的5位数字符串的表(PromoCode)。然后使用两个字段创建另一个表CampaignPromoCode:

Code varchar(5), CampaignId uniqueidentifier

通过这种方式,您可以跟踪每个广告系列的已使用广告。要获得随机的未使用的promocode,请使用以下语句:

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()

答案 3 :(得分:0)

这里的底线是你应该回到管理层并告诉他们强制100%绝对唯一的要求是一个非常成本高昂的要求,你可以获得99.9999%的独特性,只需花费一小部分费用。然后使用roryap的代码生成一个随机的,大部分是唯一的代码。