I would like to allow users to choose the exact length, or less than / more than count o characters to be generated (in a password generator).
For example i have done:
// the longivity of the generated string
var stringChars = new char[int.Parse(TextBox2.Text)];
var random = new Random();
for (int i = 0; i < stringChars.Length; i++)
{
// abc has been declared before, it is simply ABCD... for character generation
stringChars[i] = abc[random.Next(abc.Length)];
}
var finalString = new String(stringChars);
// this is the result box
TextBox1.Text = finalString;
Now my problem is if user enters for eg. 10 and wants less than 10 characters of generated string, what should I do?
You could do for example something like this (with the power of Linq):
public string GeneratePassword(string abc, int minLenght, int maxLenght)
{
var random = new Random();
var chars = Enumerable
.Range(0, random.Next(minLenght, maxLenght + 1)) // Generate a range between the min and max.
.Select(x => abc[random.Next(abc.Length)]) // Select a random character from the abc.
.ToList();
// Concatenate the string.
return string.Join(string.Empty, chars);
}
You have to using the System.Linq
Usage:
var input = 10;
var abc = "abcde";
var maxPasswordLength = 100;
var minPasswordLength = 1;
// More than the input.
GeneratePassword(abc, input + 1, maxPasswordLength);
// Less than the input.
GeneratePassword(abc, minPasswordLength, input - 1);
// Exact length.
GeneratePassword(abc, input, input);
public class Program
{
private const int MAX_LENGTH = 50;
static void Main(string[] args)
{
var less = GeneratedLessThan(12);
var more = GeneratedMoreThan(12);
Console.WriteLine($"Less Than : {less} ({less.Length})");
Console.WriteLine($"More Than : {more} ({more.Length})");
Console.ReadLine();
}
static char[] ABC()
{
List<char> list = new List<char>();
for (char i = 'A'; i <= 'Z'; i++)
{
list.Add(i);
}
return list.ToArray();
}
static string GeneratedLessThan(int max) => GeneratedString(0, max);
static string GeneratedMoreThan(int min) => GeneratedString(min, MAX_LENGTH);
static string GeneratedString(int min, int max)
{
StringBuilder builder = new StringBuilder();
var abc = ABC();
var rnd = new Random();
for (int i = 0; i <= rnd.Next(min, max); i++)
{
builder.Append(abc[rnd.Next(abc.Length)]);
}
return builder.ToString();
}
}
Maybe you dont need ABC function.
Ouput :
Less Than : IORS (4)
More Than : BSVPFZVQRWZTSPYDI (17)
Related
I have a StringBuilder result and I want to reverse it but in C# the StringBuilder doesn't support .Reverse() so first I cast it to a string and then I reverse it and add a "$" to the end of string.
but the answer is like this:
System.Linq.Enumerable+<ReverseIterator>d__75`1[System.Char]" string
how can I fix this?
StringBuilder result = new StringBuilder();
List<string> matrix = new List<string>();
List<int> indexes = new List<int>();
for (int i = 0; i < bwt.Length; i++)
{
matrix.Add("" + bwt[i]);
indexes.Add(i);
}
indexes.Sort((o1, o2) => matrix[o1].CompareTo(matrix[o2]));
int current = indexes[0];
for (int i = 0; i < bwt.Length - 1; i++)
{
int index = indexes.IndexOf(current);
string next = bwt[index].ToString();
result.Append(next);
current = index;
}
// return result.ToString().ToString() + "$";
StringBuilder allows you to access and manipulate the characters through their indexes.
string stringToReverse = "abcdefghijk";
var sb = new StringBuilder(stringToReverse);
for (int i = 0, j = sb.Length - 1; i < sb.Length / 2; i++, j--) {
char temp = sb[i];
sb[i] = sb[j];
sb[j] = temp;
}
string reversed = sb.ToString();
But I made a Test which shows that #Mendhak's version is faster. One million repetitions with strings of length 100
StringBuilder: 974 ms
Mendhak: 209 ms
So on my PC it takes just 209 ns to reverse the string with Mendhak's solution. Just because a solution looks faster it must not be faster. Array.Reverse calls the external method private static extern bool TrySZReverse(Array array, int index, int count); which is highly optimized.
The test:
static class ReverseString
{
const string stringToReverse = "abcdex.dfkjvhw4o5i8yd,vfjhe4iotuwyflkcjadhrlniqeuyfmln mclf8yuertoicer,tpoirsd,kfngoiw5r8t7ndlrgjhfg";
public static string TestStringBuilder()
{
var sb = new StringBuilder(stringToReverse);
for (int i = 0, j = sb.Length - 1; i < sb.Length / 2; i++, j--) {
char temp = sb[i];
sb[i] = sb[j];
sb[j] = temp;
}
return sb.ToString();
}
// By Mendhak
public static string TestArrayReverse()
{
char[] arr = stringToReverse.ToString().ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
public static void Compare()
{
string result1 = TestStringBuilder();
string result2 = TestArrayReverse();
Console.WriteLine($"Are result1 and 2 equal? {result1 == result2}");
Measure("StringBuilder", TestStringBuilder);
Measure("Array.Reverse", TestArrayReverse);
Console.ReadKey();
}
public static void Measure(string method, Func<string> sut)
{
const int NTests = 1000000;
var stopWatch = new Stopwatch();
stopWatch.Start();
for (int i = 0; i < NTests; i++) {
sut();
}
stopWatch.Stop();
Console.WriteLine($"{method} = {stopWatch.ElapsedMilliseconds} ms");
}
}
You will need to take a few extra steps to reverse your string. Build it as you normally would in your stringbuilder (result), then
char[] arr = result.ToString().ToCharArray();
Array.Reverse(arr);
return new string(arr) + "$";
I am currently trying to make a random password generator.
My code works fine if I only pick one type of symbols.
What's the best way to make my code to word for more than one type?
Also what parameters would you add to make the password more secured?
I am thinking of adding an if loop to check if there are more than two same letters, symbols or numbers in a row.
That's how my interface looks like:
and that is my code:
public partial class Form1 : Form
{
// Max number of identical characters in a row
const int Maximum_Identical = 2;
// lower case chars
const string lower_chars = "abcdefghijklmnopqrstuvwxyz";
// capital chars
const string capital_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// numbers
const string numbers = "0123456789";
// symbols
const string symbols = #"!#$%&*#\";
// password lenght
int lenght;
private void button1_Click(object sender, EventArgs e)
{
//use stringbuilder so I can add more chars later
StringBuilder password = new StringBuilder();
//take max lenght from numericUpDown
lenght = Convert.ToInt32(numericUpDown1.Value);
// random instance so I can use Next and don't get loops
Random rdm = new Random();
if (small_letters__Box.Checked)
{
//add a random small character to pass untill it reaches the selected lenght
while (lenght-- > 0 )
{
password.Append(lower_chars[rdm.Next(lower_chars.Length)]);
}
}
if (capital_letters__Box.Checked)
{
//add a random capital character to pass untill it reaches the selected lenght
while (lenght-- > 0)
{
password.Append(capital_chars[rdm.Next(capital_chars.Length)]);
}
}
if (numbers_Box.Checked)
{
//add a random character to pass untill it reaches the selected lenght
while (lenght-- > 0)
{
password.Append(numbers[rdm.Next(numbers.Length)]);
}
}
if (symbols_Box.Checked)
{
//add a random character to pass untill it reaches the selected lenght
while (lenght-- > 0)
{
password.Append(symbols[rdm.Next(symbols.Length)]);
}
}
textBox1.Text = password.ToString();
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
}
}
Your password generation has 2 steps.
Determine the character set
Create a password randomly from the character set of length n
Function 1 creates the character set:
// Make sure you have using System.Linq;
private List<char> GetCharacterSet()
{
IEnumerable<char> returnSet = new char[]{};
if (small_letters__Box.Checked)
{
returnSet = returnSet.Append(lower_chars);
}
if (capital_letters__Box.Checked)
{
returnSet = returnSet.Append(capital_chars);
}
if (numbers_Box.Checked)
{
returnSet = returnSet.Append(numbers);
}
if (symbols_Box.Checked)
{
returnSet = returnSet.Append(symbols);
}
return returnSet.ToList();
}
Function 2 creates a password of given length from your character set
private string GetPassword(int length, List<char> characterSet)
{
if(characterSet.Count < 1)
{
throw new ArgumentException("characterSet contains no items!");
}
if(length < 1)
{
return "";
}
Random rdm = new Random();
StringBuilder password = new StringBuilder();
for(int i = 0; i < length; i++){
int charIndex = rdm.Next(0, characterSet.Count)
password.Append(characterSet[charIndex]);
}
return password.ToString();
}
Then simply rig your button click event handler to call these functions and display the resulting password.
below code is my already written code which I wrote more than a couple of years ago and I still use it in my many of my projects where needed, it covers all you are in need of
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using System.Threading;
public static class ArrayExtentions
{
public static object[] Shuffle(this object[] array)
{
var alreadySwaped = new HashSet<Tuple<int, int>>();
var rndLoopCount = RandomUtils.GetRandom(Convert.ToInt32(array.Length / 4), Convert.ToInt32((array.Length / 2) + 1));
for (var i = 0; i <= rndLoopCount; i++)
{
int rndIndex1 = 0, rndIndex2 = 0;
do
{
rndIndex1 = RandomUtils.GetRandom(0, array.Length);
rndIndex2 = RandomUtils.GetRandom(0, array.Length);
} while (alreadySwaped.Contains(new Tuple<int, int>(rndIndex1, rndIndex2)));
alreadySwaped.Add(new Tuple<int, int>(rndIndex1, rndIndex2));
var swappingItem = array[rndIndex1];
array[rndIndex1] = array[rndIndex2];
array[rndIndex2] = swappingItem;
}
return array;
}
}
public class RandomUtils
{
private static readonly ThreadLocal<Random> RndLocal = new ThreadLocal<Random>(() => new Random(GetUniqueSeed()));
private static int GetUniqueSeed()
{
long next, current;
var guid = Guid.NewGuid().ToByteArray();
var seed = BitConverter.ToInt64(guid, 0);
do
{
current = Interlocked.Read(ref seed);
next = current * BitConverter.ToInt64(guid, 3);
} while (Interlocked.CompareExchange(ref seed, next, current) != current);
return (int)next ^ Environment.TickCount;
}
public static int GetRandom(int min, int max)
{
Contract.Assert(max >= min);
return RndLocal.Value.Next(min, max);
}
public static int GetRandom(int max)
{
return RndLocal.Value.Next(max);
}
public static double GetRandom()
{
return RndLocal.Value.NextDouble();
}
}
public class StringUtility
{
private const string UpperAlpha = "ABCDEFGHIJKLMNOPQRSTUWXYZ";
private const string LowerAlpha = "abcdefghijklmnopqrstuwxyz";
private const string Numbers = "0123456789";
private const string SpecialChars = "~!##$%^&*()_-+=.?";
private static string CreateSourceString(bool includeLowerCase, bool includeUpperCase, bool includenumbers, bool includeSpChars)
{
Contract.Assert(includeLowerCase || includeUpperCase || includenumbers || includeSpChars);
var sb = new StringBuilder();
if (includeLowerCase) sb.Append(LowerAlpha);
if (includeUpperCase) sb.Append(UpperAlpha);
if (includenumbers) sb.Append(Numbers);
if (includeSpChars) sb.Append(SpecialChars);
return sb.ToString();
}
private static string GenerateString(string sourceString, int length = 6)
{
var rndString = Shuffle(sourceString);
var builder = new StringBuilder();
for (var i = 0; i < length; i++)
builder.Append(rndString[RandomUtils.GetRandom(0, rndString.Length)]);
return builder.ToString();
}
public static string GenerateRandomString(int length = 6,
bool includenumbers = false,
bool includeSpChars = false)
{
var sourceStr = CreateSourceString(true, true, includenumbers, includeSpChars);
return GenerateString(sourceStr, length);
}
public static string GenerateRandomString(int minLength,
int maxLength,
bool includenumbers = false,
bool includeSpChars = false)
{
if (maxLength < minLength) maxLength = minLength;
var len = RandomUtils.GetRandom(minLength, maxLength + 1);
return GenerateRandomString(len, includenumbers, includeSpChars);
}
public static string Shuffle(string str)
{
var alreadySwaped = new HashSet<Tuple<int, int>>();
var rndLoopCount = RandomUtils.GetRandom(Convert.ToInt32(str.Length / 4), Convert.ToInt32((str.Length / 2) + 1));
var strArray = str.ToArray();
for (var i = 0; i <= rndLoopCount; i++)
{
int rndIndex1 = 0, rndIndex2 = 0;
do
{
rndIndex1 = RandomUtils.GetRandom(0, str.Length);
rndIndex2 = RandomUtils.GetRandom(0, str.Length);
} while (alreadySwaped.Contains(new Tuple<int, int>(rndIndex1, rndIndex2)));
alreadySwaped.Add(new Tuple<int, int>(rndIndex1, rndIndex2));
var swappingChar = strArray[rndIndex1];
strArray[rndIndex1] = strArray[rndIndex2];
strArray[rndIndex2] = swappingChar;
}
return new string(strArray);
}
public static string GeneratePassword(PasswordComplexity complexityLevel)
{
switch (complexityLevel)
{
case PasswordComplexity.Simple: return GenerateSimplePassword();
case PasswordComplexity.Medium: return GenerateMediumPassword();
case PasswordComplexity.Strong: return GenerateStrongPassword();
case PasswordComplexity.Stronger: return GenerateStrongerPassword();
}
return null;
}
private static string GenerateSimplePassword()
{
return GenerateRandomString(6, 9);
}
private static string GenerateMediumPassword()
{
var passLen = RandomUtils.GetRandom(6, 10);
var numCount = RandomUtils.GetRandom(1, 3);
var alphaStr = GenerateRandomString(passLen - numCount);
var numStr = GenerateString(Numbers, numCount);
var pass = alphaStr + numStr;
return Shuffle(pass);
}
private static string GenerateStrongPassword()
{
var lowerCharCount = RandomUtils.GetRandom(2, 5);
var upperCharCount = RandomUtils.GetRandom(2, 5);
var numCount = RandomUtils.GetRandom(2, 4);
var spCharCount = RandomUtils.GetRandom(2, 4);
var lowerAlphaStr = GenerateString(LowerAlpha, lowerCharCount);
var upperAlphaStr = GenerateString(UpperAlpha, upperCharCount);
var spCharStr = GenerateString(SpecialChars, spCharCount);
var numStr = GenerateString(Numbers, numCount);
var pass = lowerAlphaStr + upperAlphaStr + spCharStr + numStr;
return Shuffle(pass);
}
private static string GenerateStrongerPassword()
{
var lowerCharCount = RandomUtils.GetRandom(5, 12);
var upperCharCount = RandomUtils.GetRandom(4, 8);
var numCount = RandomUtils.GetRandom(4, 6);
var spCharCount = RandomUtils.GetRandom(4, 6);
var lowerAlphaStr = GenerateString(LowerAlpha, lowerCharCount);
var upperAlphaStr = GenerateString(UpperAlpha, upperCharCount);
var spCharStr = GenerateString(SpecialChars, spCharCount);
var numStr = GenerateString(Numbers, numCount);
var pass = lowerAlphaStr + upperAlphaStr + spCharStr + numStr;
return Shuffle(Shuffle(pass));
}
public enum PasswordComplexity
{
Simple, Medium, Strong, Stronger
}
}
I write this code for you. You can just copy and use it. All of my code is just a method that you can pass appropriate arguments and it gives you back a completely randomized password. I test it several times before answering your question, It works well.
private string GeneratePassword(bool useCapitalLetters, bool useSmallLetters, bool useNumbers, bool useSymbols, int passLenght)
{
Random random = new Random();
StringBuilder password = new StringBuilder(string.Empty);
//This for loop is for selecting password chars in order
for (int i = 0;;)
{
if (useCapitalLetters)
{
password.Append((char)random.Next(65, 91)); //Capital letters
++i; if (i >= passLenght) break;
}
if (useSmallLetters)
{
password.Append((char)random.Next(97, 122)); //Small letters
++i; if (i >= passLenght) break;
}
if (useNumbers)
{
password.Append((char)random.Next(48, 57)); //Number letters
++i; if (i >= passLenght) break;
}
if (useSymbols)
{
password.Append((char)random.Next(35, 38)); //Symbol letters
++i; if (i >= passLenght) break;
}
}
//This for loop is for disordering password characters
for (int i = 0; i < password.Length; ++i)
{
int randomIndex1 = random.Next(password.Length);
int randomIndex2 = random.Next(password.Length);
char temp = password[randomIndex1];
password[randomIndex1] = password[randomIndex2];
password[randomIndex2] = temp;
}
return password.ToString();
}
an answer with complete randomize char and using the max repeat of char, i have added a shuffle string function:
const int Maximum_Identical = 2; // Max number of identical characters in a row
const string lower_chars = "abcdefghijklmnopqrstuvwxyz"; // lower case chars
const string capital_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //capital chars
const string numbers = "0123456789"; //numbers
const string symbols = #"!#$%&*#\"; //symbols
int lenght = 6; //
bool lowercase = true, capital=true, num=true, sym=true;
List<char[]> PasswordSet = new List<char[]>();
List<char[]> charSet = new List<char[]>();
List<int[]> countSet = new List<int[]>();
if (lowercase) charSet.Add(lower_chars.ToArray());
if (capital) charSet.Add(capital_chars.ToArray());
if (num) charSet.Add(numbers.ToArray());
if (sym) charSet.Add(symbols.ToArray());
foreach(var c in charSet)
countSet.Add(new int[c.Length]);
Random rdm = new Random();
//we create alist with each type with a length char (max repeat char included)
for(int i = 0; i < charSet.Count;i++)
{
var lng = 1;
var p0 = "";
while (true)
{
var ind = rdm.Next(0, charSet[i].Length);
if (countSet[i][ind] < Maximum_Identical )
{
countSet[i][ind] += 1;
lng++;
p0 += charSet[i][ind];
}
if (lng == lenght) break;
}
PasswordSet.Add(p0.ToArray());
}
//generate a password with the desired length with at less one char in desired type,
//and we choose randomly in desired type to complete the length of password
var password = "";
for(int i = 0; i < lenght; i++)
{
char p;
if (i < PasswordSet.Count)
{
int id;
do
{
id = rdm.Next(0, PasswordSet[i].Length);
p = PasswordSet[i][id];
} while (p == '\0');
password += p;
PasswordSet[i][id] = '\0';
}
else
{
int id0;
int id1;
do
{
id0 = rdm.Next(0, PasswordSet.Count);
id1 = rdm.Next(0, PasswordSet[id0].Length);
p = PasswordSet[id0][id1];
} while (p == '\0');
password += p;
PasswordSet[id0][id1] = '\0';
}
}
//you could shuffle the final password
password = Shuffle.StringMixer(password);
shuffle string function:
static class Shuffle
{
static System.Random rnd = new System.Random();
static void Fisher_Yates(int[] array)
{
int arraysize = array.Length;
int random;
int temp;
for (int i = 0; i < arraysize; i++)
{
random = i + (int)(rnd.NextDouble() * (arraysize - i));
temp = array[random];
array[random] = array[i];
array[i] = temp;
}
}
public static string StringMixer(string s)
{
string output = "";
int arraysize = s.Length;
int[] randomArray = new int[arraysize];
for (int i = 0; i < arraysize; i++)
{
randomArray[i] = i;
}
Fisher_Yates(randomArray);
for (int i = 0; i < arraysize; i++)
{
output += s[randomArray[i]];
}
return output;
}
}
There you go :
string[] charList =
{
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"0123456789",
"#\"!#$%&*#\\"
};
int desiredPasswordLength = 12;
var randomNumberGenerator = new Random();
string generatedPassword = "";
for (int i = randomNumberGenerator.Next() % 4; desiredPasswordLength > 0; i = (i+1) % 4)
{
var takeRandomChars = randomNumberGenerator.Next() % 3;
for (int j = 0; j < takeRandomChars; j++)
{
var randomChar = randomNumberGenerator.Next() % charList[i].Length;
char selectedChar = charList[i][randomChar % charList[i].Length];
generatedPassword = string.Join("", generatedPassword, selectedChar);
}
desiredPasswordLength -= takeRandomChars;
}
Console.WriteLine("Generated password: {0}",generatedPassword);
private static string GeneratorPassword(UInt16 length = 8)
{
const string chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0";
System.Text.StringBuilder sb = new System.Text.StringBuilder();
Random rnd = new Random();
System.Threading.Thread.Sleep(2);
for (int i = 0; i < length; i++)
{
int index = 0;
if (i % 3 == 0)
{
index = rnd.Next(0, 10);
}
else if (i % 3 == 1)
{
index = rnd.Next(10, 36);
}
else
{
index = rnd.Next(36, 62);
}
sb.Insert(rnd.Next(0, sb.Length), chars[index].ToString());
}
return sb.ToString();
}
static void Main(string[] args)
{
for (int j= 0; j < 100; j++)
{
Console.WriteLine( GeneratorPassword());
}
Console.ReadLine();
}
public void generate()
{
string alphabets = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string small_alphabets = "abcdefghijklmnopqrstuvwxyz";
string numbers = "1234567890";
string characters = numbers;
characters += alphabets + small_alphabets + numbers;
int length =6;
string opt = string.Empty;
for (int i = 0; i < length; i++)
{
string character = string.Empty;
do
{
int index = new Random().Next(0, characters.Length);
character = characters.ToCharArray()[index].ToString();
} while (otp.IndexOf(character) != -1);
otp += character;
}
string str= otp;
}
This is my code, which is not working for me.
I want to try small alphabet, capital alphabet and 0 to 9 number combination.
Here is the code :
var chars1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
var stringChars1 = new char[6];
var random1 = new Random();
for (int i = 0; i < stringChars1.Length; i++)
{
stringChars1[i] = chars1[random1.Next(chars1.Length)];
}
var str= new String(stringChars1);
This code will give you numeric otp of n digits.
public static int GenerateOTP(int digits)
{
if (digits < 3)
return new Random().Next(10, 99);
else
return new Random().Next(MultiplyNTimes(digits), MultiplyNTimes(digits + 1) - 1);
}
private static int MultiplyNTimes(int n)
{
if (n == 1)
return 1;
else
return 10 * MultiplyNTimes(n - 1);
}
I am trying to generate a random alphanumeric array that consist of 3 letters and 6 digits. The entire array must be random. The only way I could think of is generating 2 individual random arrays and then merging them and randomizing the merged array. Any help would be appreciated. I specifically need help on ensuring that the correct number of variable types are stored. Here is my semi-working code:
static void Main(string[] args)
{
var alphabetic = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var numeric = "0123456789";
var stringChars = new char[9];
var random = new Random();
for (int i = 0; i < 3; i++)
{
stringChars[i] = alphabetic[random.Next(alphabetic.Length)];
}
for(int i = 3; i< stringChars.Length; i++)
{
stringChars[i] = numeric[random.Next(numeric.Length)];
}
var ranChars = new char[9];
var semisorted = new String(stringChars);
for (int i=0; i< ranChars.Length; i++)
{
ranChars[i] = semisorted[random.Next(semisorted.Length)];
}
var final = new string(ranChars);
Console.WriteLine("{0}", final);
Console.ReadLine();
}
You're close. But the problem here is that you're selecting randomly from the "semi-sorted" array, while what's really necessary at that point is picking a random permutation. One way to do that is with a Fisher-Yates shuffle.
So combining that with the code you had that worked: (not tested)
for (int i = 0; i < 3; i++)
{
stringChars[i] = alphabetic[random.Next(alphabetic.Length)];
}
for(int i = 3; i< stringChars.Length; i++)
{
stringChars[i] = numeric[random.Next(numeric.Length)];
}
int n = stringChars.Length;
while (n > 1)
{
int k = random.Next(n--);
char temp = stringChars[n];
stringChars[n] = stringChars[k];
stringChars[k] = temp;
}
string result = new string(stringChars);
Harold's answer is way cleaner, but here's another approach for the whole '100 ways to do the same thing in programming' concept. [Edit: Doh, I reversed the number of digits and letters. Here's a fix:]
public static void Main(string[] args)
{
var random = new Random();
var finalString = string.Empty;
var finalArray = new string[9];
for (var i = 0; i < 3; i++)
{
var alphabet = random.Next(0, 26);
var letter = (char) ('a' + alphabet);
finalArray[i] = letter.ToString().ToUpper();
}
for (var i = 3; i < 9; i++)
{
var number = random.Next(0, 9);
finalArray[i] = number.ToString();
}
var shuffleArray = finalArray.OrderBy(x => random.Next()).ToArray();
for (var i = 0; i < finalArray.Length; i++)
{
finalString += shuffleArray[i];
}
Console.WriteLine(finalString);
Console.ReadKey();
}
I'm new to C#. I have a short form and a long form of a client code. The short form is some alpha characters and some numeric ones (ABC12), while the long form is always 15 characters long with the space between the alpha and the numeric parts padded out with zeros (ABC000000000012). I need to be able to convert from the short form to the long. The code below is how I've got it to work - is this the best way to do this?
public string ExpandCode(string s)
{
// s = "ABC12"
int i = 0;
char c;
bool foundDigit = false;
string o = null;
while (foundDigit == false)
{
c = Convert.ToChar(s.Substring(i, 1));
if (Char.IsDigit(c))
{
foundDigit = true;
o = s.Substring(0, i) + new String('0', 15-s.Length) + s.Substring(i,s.Length-i);
}
i += 1;
}
return (o); //o = "ABC000000000012"
}
Your code is basically correct, however it could be slow, since String.Substring(...) creates a new string every time called.
I also suggest that you use the built-in functions of the .NET api for accomplishing your tasks, which can make coding easier a lot:
private char[] numbers = new char[]{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
public string ExpandCode(string s)
{
//Find the first numeric char.
int index = s.IndexOfAny(numbers);
//Insert zeros and return the result.
return s.Insert(index, new String('0', 15 - s.Length));
}
Take a look at this:
public string ExpandCode(string s)
{
var builder = new StringBuilder(s);
var index = Array.FindIndex(s.ToArray(), x => char.IsDigit(x));
while (builder.Length < 15)
{
builder.Insert(index, '0');
}
return builder.ToString();
}
I assume that string are always letter -> digit (like "abc123" or "ab1234").
The purer, the faster
public static string ExpandCode4(string s)
{
char[] res = new char[15];
int ind = 0;
for (int i = 0; i < s.Length && s[i] >= 'A'; i++)
res[ind++] = s[i];
int tillDigit = ind;
for (int i = 0; i < 15 - s.Length; i++)
res[ind++] = '0';
for (int i = 0; i < s.Length - tillDigit; i++)
res[ind++] = s[tillDigit + i];
return new string(res);
}
Benchmark for all the answers is as follows,
internal class Program
{
private static void Main(string[] args)
{
var inputs = new List<string>();
for (int i = 0; i < 10000000; i++)
{
inputs.Add("ABC1234");
}
var n1 = DateTime.Now;
inputs.ForEach(i => ExpandCode1(i));
var r1 = (DateTime.Now - n1).Ticks;
var n2 = DateTime.Now;
inputs.ForEach(i => ExpandCode2(i));
var r2 = (DateTime.Now - n2).Ticks;
var n3 = DateTime.Now;
inputs.ForEach(i => ExpandCode3(i));
var r3 = (DateTime.Now - n3).Ticks;
var n4 = DateTime.Now;
inputs.ForEach(i => ExpandCode4(i));
var r4 = (DateTime.Now - n4).Ticks;
var results = new List<Result>()
{
new Result() {Name = "1", Ticks = r1},
new Result() {Name = "2", Ticks = r2},
new Result() {Name = "3", Ticks = r3},
new Result() {Name = "4", Ticks = r4}
};
results.OrderBy(r => r.Ticks).ToList().ForEach(Console.WriteLine);
Console.ReadKey();
}
public static string ExpandCode4(string s)
{
char[] res = new char[15];
int ind = 0;
for (int i = 0; i < s.Length && s[i] >= 'A'; i++)
res[ind++] = s[i];
int tillDigit = ind;
for (int i = 0; i < 15 - s.Length; i++)
res[ind++] = '0';
for (int i = 0; i < s.Length - tillDigit; i++)
res[ind++] = s[tillDigit + i];
return new string(res);
}
public static string ExpandCode1(string s)
{
char[] numbers = new char[] { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };
//Find the first numeric char.
int index = s.IndexOfAny(numbers);
//Insert zeros and return the result.
return s.Insert(index, new String('0', 15 - s.Length));
}
public static string ExpandCode2(string s)
{
var builder = new StringBuilder(s);
var index = Array.FindIndex(s.ToArray(), x => char.IsDigit(x));
while (builder.Length < 15)
{
builder.Insert(index, '0');
}
return builder.ToString();
}
public static string ExpandCode3(string s)
{
var match = Regex.Match(s, #"([^\d]+)(\d+)");
var letters = match.Groups[1].Value;
var numbers = int.Parse(match.Groups[2].Value);
var formatString = "{0}{1:d" + (15 - letters.Length) + "}";
var longForm = string.Format(formatString, letters, numbers);
return longForm;
}
}
public class Result
{
public long Ticks { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name + " - " + Ticks;
}
}
You can use string.Format() to take care of the padding for you. I used regex (and not in a very robust manner) to parse out the letters and numbers but you may be able to do this more efficiently another way.
The key point is that we dynamically figure out how many zero's we need, and then use a format string of the form X:dY where X = format ordinal and Y = the number of zeros you wish to pad.
var match = Regex.Match("ABC12", #"([^\d]+)(\d+)");
var letters = match.Groups[1].Value;
var numbers = int.Parse(match.Groups[2].Value);
var formatString = "{0}{1:d" + (15 - letters.Length) + "}";
var longForm = string.Format(formatString, letters, numbers);