根据以下代码,我需要根据方法输入在不同情况下生成一个字符串。我的问题是我想要生成 9A9A (至少1个数字和1个字母)或 9A9A9A (至少2个数字和2个字母)。在大多数情况下,这种情况不符合。
private AuthMessage GetAuthCode(string CodeType) //(out string Message)
{
Guid Guid = Guid.NewGuid();
Random Random = new Random();
string AuthCode = string.Empty;
string RefCode = string.Empty;
RefCode = Guid.ToString("N");
switch (CodeType)
{
case "0": //9999
{
AuthCode = Random.Next(1000, 9999).ToString();
break;
}
case "1": //99999
{
AuthCode = Random.Next(10000, 99999).ToString();
break;
}
case "2": //999999
{
AuthCode = Random.Next(100000, 999999).ToString();
break;
}
case "3": //999-999
{
AuthCode = Regex.Replace(Random.Next(100000, 999999).ToString(), @"^(.{3})(.{3})$", "$1-$2");
break;
}
case "4": //9A9A
{
AuthCode = Guid.ToString("N").Substring(14, 4).ToUpper();
break;
}
case "5": //9A9A9
{
AuthCode = Guid.ToString("N").Substring(15, 5).ToUpper();
break;
}
case "6": //9A9A9A
{
AuthCode = Guid.ToString("N").Substring(6, 6).ToUpper();
break;
}
case "7": //9A9-A9A
{
AuthCode = Regex.Replace(Guid.ToString("N").Substring(6, 6), @"(.{3})(.{3})", @"$1-$2").ToUpper();
break;
}
case "8": //9A9-A9A
{
AuthCode = Regex.Replace(Regex.Replace(Convert.ToBase64String(Guid.ToByteArray()), "[/+=]", "").Substring(0, 6), @"(.{3})(.{3})", @"$1-$2").ToUpper();
break;
}
default:
{
AuthCode = Random.Next(1000, 9999).ToString();
break;
}
}
AuthMessage Response = new AuthMessage();
Response.AuthCode = AuthCode;
Response.RefCode = RefCode;
return Response;
}
答案 0 :(得分:4)
Guid
表示由十六进制数字组成,即字符0
- 9
和a
- f
。依靠它来获得字母和数字的混合的问题在于,任何给定位置的字符可以是字母或十进制数字,概率倾斜大约5:3,有利于十进制数字。
如果要生成特定的数字和字母组合,则应该一次生成一个字符,而不依赖于Guid
表示。
答案 1 :(得分:2)
我以为我会去 - 它给了我一个被嘲笑的好机会。这不是生成代码的最有效方法,但它应该是相当随机的。
private string GetAuthCode(string CodeType)
{
var patterns = new Dictionary<char, Func<Char>>()
{
{ '9', () => RandomBytes().Where(x => x >= '0' && x <= '9').First() },
{ 'A', () => RandomBytes().Where(x => x >= 'A' && x <= 'Z').First() },
{ '-', () => '-' },
};
return
String.IsNullOrEmpty(CodeType)
? ""
: patterns[CodeType[0]]().ToString() + GetAuthCode(CodeType.Substring(1));
}
private IEnumerable<char> RandomBytes()
{
using (var rng = System.Security.Cryptography.RNGCryptoServiceProvider.Create())
{
var bytes = new byte[256];
while (true)
{
rng.GetBytes(bytes);
foreach (var @byte in bytes)
{
yield return (char)@byte;
}
}
}
}
现在,由于实现迭代器方法的时髦猴子状态机,尽管有while (true)
,此代码仍处理RNG。
我稍微简化了GetAuthCode
方法,但我认为这证明了生成代码的合适方法。
答案 2 :(得分:-2)
public class TokenCreator
{
private Random random = new Random();
private const string[] chars= "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
public static string CreateToken(int length)
{
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
}
AuthCode = TokenCreator.CreateToken(5);
这种实现对您没什么帮助。但同样,它并不能保证您获得字母数字组合。有时您可能只获得字母表,有时您可能只获得数字。虽然机会很少。
答案 3 :(得分:-2)
OverView 以下代码使用了Regex.Replace
IsMatch
,XXXXXX
允许用户创建任意长度模式,例如XX-XX
或X
将用随机字符或字母替换任何XX-XX
。
例如,A(-1d
可以返回XXXX
或仅使用短划线A(1d
返回Web.Security.Membership.GeneratePassword
。
安全强>
它使用// This pattern enforces our rule that a pwd must have one letter and one digit.
string pattern = @" # This regex pattern enforces the rules before returning matching
(?=.*[a - zA - Z]) # Somewhere there is a an alphabectic character
(?=.*\d) # Somewhere there is a number; if no number found return no match.
(.+) # Successful match, rules are satisfied. Return match";
Random rn = new Random(); // Used to cherry pick from chars to use.
// Creates 48 alpha and non alpha (at least 10 non digit alphas) random characters.
string charsToUse = System.Web.Security.Membership.GeneratePassword(48, 5);
// When replacement is done, replace an `X` matched with a random char.
MatchEvaluator RandomChar = delegate (Match m)
{
return charsToUse[rn.Next(charsToUse.Length)].ToString();
};
Func<string, string> Validate =
(string str) => Regex.IsMatch(str, pattern, RegexOptions.IgnorePatternWhitespace)
? str : string.Empty; // return empty on failure.
string pwdClear = string.Empty;
// Generate valid pwd based on rules. Loop until rules are met.
while (string.IsNullOrEmpty(pwdClear))
pwdClear = Validate(Regex.Replace("XXXX-XXXX-XXXX-XXXX-XXXX", "X", RandomChar));
// Create a secure string for the password for transportation.
SecureString ss = new SecureString();
pwdClear.ToList()
.ForEach(chr => ss.AppendChar(chr));
来获取48个随机字符,数字和不包含的字符串。然后根据所需的模式从该随机字符中剔除一个明确的密码。
(至少1个数字和1个字母)
这在验证正则表达式中完成,它确保至少有一个字母字符和一个数字。调用该generate方法,直到该验证报告您提到的规则的有效匹配。
安全传输 最后设置一个安全字符串返回。
这个得到了
if opts.fields:
fields = ", ".join([x.strip() for x in opts.fields.split(",")])
else:
fields = ", ".join(rows.next())
qry = "INSERT INTO %s (%s) VALUES (%s);" % (table,
fields,
",".join("?"*len(rows)),)
此答案基于我博客上的非安全实施,请参阅C#: Generate a Random Sequence of Numbers and Letters From a User Defined Pattern and Characters
答案 4 :(得分:-3)
出于测试目的,当我需要生成具有特定属性的随机字符串时,我使用类似于此的东西。您可能必须根据自己的需要进行调整。
public sealed class StringGenerator
{
private static readonly char[] NumericChars = "0123456789".ToCharArray();
private static readonly char[] LowerAlphaChars = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
private static readonly char[] UpperAlphaChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
public StringGenerator(IRandom rnd)
{
Rnd = rnd ?? new SecureRandom();
}
private IRandom Rnd
{
get;
set;
}
public string Generate(int length, int minNumeric = 0, int minAlpha = 0, AlphaCase alphaCase = AlphaCase.Both)
{
if (length < 0)
{
throw new ArgumentOutOfRangeException("length");
}
if (minNumeric < 0)
{
throw new ArgumentOutOfRangeException("minNumeric");
}
if (minAlpha < 0)
{
throw new ArgumentOutOfRangeException("minAlpha");
}
if (length < minNumeric + minAlpha)
{
throw new ArgumentException();
}
if (length == 0)
{
return string.Empty;
}
var result = new char[length];
var index = 0;
foreach(var numeric in GenerateNumeric().Take(minNumeric))
{
result[index++] = numeric;
}
var alphaCharacters = GetAlphaCharacters(alphaCase);
foreach (var alpha in Generate(alphaCharacters).Take(minAlpha))
{
result[index++] = alpha;
}
var restLength = length - index;
if (restLength > 0)
{
var restCharacters = new List<char>(NumericChars.Concat(alphaCharacters));
foreach (var rest in Generate(restCharacters).Take(restLength))
{
result[index++] = rest;
}
}
// shuffle result
return new string(result.OrderBy(x => Rnd.Next()).ToArray());
}
private IList<char> GetAlphaCharacters(AlphaCase alphaCase)
{
switch (alphaCase)
{
case AlphaCase.Lower:
return LowerAlphaChars;
case AlphaCase.Upper:
return UpperAlphaChars;
case AlphaCase.Both:
default:
return new List<char>(LowerAlphaChars.Concat(UpperAlphaChars));
}
}
public IEnumerable<char> GenerateNumeric()
{
return Generate(NumericChars);
}
public IEnumerable<char> GenerateLowerAlpha()
{
return Generate(LowerAlphaChars);
}
public IEnumerable<char> GenerateUpperAlpha()
{
return Generate(UpperAlphaChars);
}
public IEnumerable<char> Generate(IList<char> characters)
{
if (characters == null)
{
throw new ArgumentNullException();
}
if (!characters.Any())
{
yield break;
}
while (true)
{
yield return characters[Rnd.Next(characters.Count)];
}
}
}
public enum AlphaCase
{
Lower,
Upper,
Both
}
public interface IRandom
{
int Next();
int Next(int maxValue);
}
public sealed class SecureRandom : IRandom
{
private readonly RandomNumberGenerator Rng = new RNGCryptoServiceProvider();
public int Next()
{
var data = new byte[sizeof(int)];
Rng.GetBytes(data);
return BitConverter.ToInt32(data, 0) & (int.MaxValue - 1);
}
public int Next(int maxValue)
{
return Next(0, maxValue);
}
public int Next(int minValue, int maxValue)
{
if (minValue > maxValue)
{
throw new ArgumentOutOfRangeException();
}
return (int)Math.Floor(minValue + ((double)maxValue - minValue) * NextDouble());
}
public double NextDouble()
{
var data = new byte[sizeof(uint)];
Rng.GetBytes(data);
var randomUint = BitConverter.ToUInt32(data, 0);
return randomUint / (uint.MaxValue + 1d);
}
}
编辑:这是如何使用条件生成随机字母数字字符串的问题的答案。正如测试目的所述。不得在安全性相关的环境中使用。
编辑2:无耻地从this answer借用,解决方案现在使用RNGCryptoServiceProvider周围的包装器。仍不确定这是否应该用于安全相关的上下文中,但至少现在它应该比仅使用Random