我需要生成优惠券代码[5到10位],仅限一次使用。生成和检查是否使用过的最佳方法是什么?
编辑:我更喜欢字母数字字符 - 亚马逊像礼品券代码必须是唯一的。
答案 0 :(得分:16)
生成优惠券代码时 - 您应该考虑是否具有可预测的序列才是您想要的。
例如,凭证代码:ABC101,ABC102,ABC103等是相当可预测的。用户可以很容易地猜出凭证代码。
为了防止这种情况发生 - 你需要一些防止随机猜测工作的方法。
两种方法:
在您的优惠券代码中嵌入校验和。
信用卡上的最后一个数字是校验和(校验位) - 当您以某种方式将其他数字相加时,可以确保有人正确输入了数字。请参阅:http://www.beachnet.com/~hstiles/cardtype.html(谷歌的第一个链接)了解如何为信用卡完成此操作。
有一个很大的密钥空间,只有人口稀少。
例如,如果您要生成1,000张优惠券 - 那么1,000,000的密钥空间意味着您应该能够使用随机生成(使用重复和顺序检查)来确保难以猜测另一个优惠券代码。
以下是使用大型密钥空间方法的示例应用程序:
static Random random = new Random();
static void Main(string[] args)
{
int vouchersToGenerate = 10;
int lengthOfVoucher = 10;
List<string> generatedVouchers = new List<string>();
char[] keys = "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890".ToCharArray();
Console.WriteLine("Vouchers: ");
while(generatedVouchers.Count < vouchersToGenerate)
{
var voucher = GenerateVoucher(keys, lengthOfVoucher);
if (!generatedVouchers.Contains(voucher))
{
generatedVouchers.Add(voucher);
Console.WriteLine("\t[#{0}] {1}", generatedVouchers.Count, voucher);
}
}
Console.WriteLine("done");
Console.ReadLine();
}
private static string GenerateVoucher(char[] keys, int lengthOfVoucher)
{
return Enumerable
.Range(1, lengthOfVoucher) // for(i.. )
.Select(k => keys[random.Next(0, keys.Length - 1)]) // generate a new random char
.Aggregate("", (e, c) => e + c); // join into a string
}
答案 1 :(得分:7)
以Will Hughes&amp;的答案为基础Shekhar_Pro(只是因为我发现这个问题很有意思)这是另一个实现,但我对你的代码长度要求有点自由。
使用base 32 encoder我发现您可以使用Tick
值生成字母数字字符串。将滴答计数编码为基数32会产生一个13个字符的字符串,可对其进行格式化以使其更具可读性。
public void GenerateCodes()
{
Random random = new Random();
DateTime timeValue = DateTime.MinValue;
// Create 10 codes just to see the random generation.
for(int i=0; i<10; ++i)
{
int rand = random.Next(3600)+1; // add one to avoid 0 result.
timeValue = timeValue.AddMinutes(rand);
byte[] b = System.BitConverter.GetBytes(timeValue.Ticks);
string voucherCode = Transcoder.Base32Encode(b);
Console.WriteLine(string.Format("{0}-{1}-{2}",
voucherCode.Substring(0,4),
voucherCode.Substring(4,4),
voucherCode.Substring(8,5)));
}
}
这是输出
AARI-3RCP-AAAAA ACOM-AAZF-AIAAA ABIH-LV7W-AIAAA ADPL-26FL-AMAAA ABBL-W6LV-AQAAA ADTP-HFIR-AYAAA ACDG-JH5K-A4AAA ADDE-GTST-BEAAA AAWL-3ZNN-BIAAA AAGK-4G3Y-BQAAA
如果您为Random
对象使用已知种子并记住已创建的代码数量,则可以继续生成代码;例如如果您需要更多代码并且想要确定您不会生成重复项。
答案 2 :(得分:3)
这是一种方法:在10000到9999999999之间生成一堆唯一数字,将其放入数据库中。每次向用户提供一个用户时,请将其标记为已使用(如果您尝试节省空间,则将其删除)。
编辑:在开头生成唯一的字母数字值。您可能需要保留它们以进行验证(正如其他人指出的那样)。
答案 3 :(得分:1)
如果您的应用仅限于使用数字数字,那么我认为时间戳(DateTime.Now.Ticks
)可以是每次获取唯一代码的好方法。您可以使用随机数字,但这将有检查已经发出的每个数字的开销。如果你也可以使用字母表,那么肯定会使用GUID。
为了检查它是否已被使用,您需要维护一个数据库并查询它以检查其有效性。
答案 4 :(得分:0)
如果您更喜欢字母数字,可以使用Guid.NewGuid()方法:
Guid g = Guid.NewGuid();
Random rn = new Random();
string gs = g.ToString();
int randomInt = rn.Next(5,10+1);
Console.WriteLine(gs.Substring(gs.Length - randomInt - 1, randomInt));
检查它是否未用于存储以前生成的代码并进行比较。
答案 5 :(得分:0)
private void AutoPurchaseVouNo1()
{
try
{
int Num = 0;
con.Close();
con.Open();
string incre = "SELECT MAX(VoucherNoint+1) FROM tbl_PurchaseAllCompany";
SqlCommand command = new SqlCommand(incre, con);
if (Convert.IsDBNull(command.ExecuteScalar()))
{
Num = 100;
txtVoucherNoInt1.Text = Convert.ToString(Num);
txtVoucherNo1.Text = Convert.ToString("ABC" + Num);
}
else
{
Num = (int)(command.ExecuteScalar());
txtVoucherNoInt1.Text = Convert.ToString(Num);
txtVoucherNo1.Text = Convert.ToString("ABC" + Num);
}
con.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex, "Error !!", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
尝试使用此方法创建优惠券号码,如ABC100,ABC101,ABC102等。
答案 6 :(得分:0)
试试此代码
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var stringChars = new char[15];
for (int i = 0; i < stringChars.Length; i++)
{
stringChars[i] = chars[random.Next(chars.Length)];
}