A good way to check a chars 'integrity' - c#

I'm working on making my own password generator; and I want it to create passwords that contain numbers, lowercase-letters, and uppercase-letters.
I am writing the program in C#, using Visual Studio.
Say I use the code below:
Random Rand = new Random();
Char C = Convert.ToChar(Rand.Next(0x30, 0x5A));
How could I make my program check whether (C) is equal to a number or a uppercase-letter?

Use Char.IsDigit (for decimal digits), or Char.IsNumber and Char.IsUpper.
These are all static methods defined on the Char structure.
An example, as requested:
if(Char.IsNumber(C))
{
// Character is marked as a unicode number
}

you can check if:
int ordinal = (int)C;
if(( ordinal >= 65 && ordinal <= 90 ) || (ordinal >= 48 && ordinal <= 57))
{
Console.WriteLine( C + " is an uppercase A-Z or 0-9!" );
}

A better (and standard) way, is to create an 'alphabet' string of allowable characters and then generate a random index into the string, to select an allowable character.
Much better than first generating a random character and then checking if it is allowable.
"0123456789abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
Note the removed lowercase 'l' (looks like 1). You should remove any others such as zero versus 'O' possibly...or whatever your password rules allow)
Here's an example of using this technique to generate random strings:
public static class RandomUtils
{
private static readonly Random random = new Random();
public static string GenerateRandomAlphaNumericString(int length)
{
const string alpha =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
return GenerateRandomString(length, alpha);
}
public static string GenerateRandomString(int length, string alphabet)
{
int maxlen = alphabet.Length;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++)
{
sb.Append(alphabet[random.Next(0, maxlen)]);
}
return sb.ToString();
}
}

Probably just use Char.IsNumber and Char.IsUpper methods:
see:
http://msdn.microsoft.com/en-us/library/9s91f3by.aspx
http://msdn.microsoft.com/en-us/library/yk2b3t2y.aspx
if (C.IsNumber || C.IsUpper)
{
// password code!
}
(don't write your own password generator, unless it's just for fun though).

Related

How to skip values in Random.Range? In Unity/C#?

facing issue with randomising the randomLetter for non latin script. in my script, in the unicode characters table, 4 unicode values are non existent. need to skip those characters while Random.Range() is running. what is the workaround? declare an array? or declare a list? or something else? please help.
Working code for Latin script:
{
private void OnEnable()
{
var i = UnityEngine.Random.Range(0, 26);
_randomLetter = (char) ('a' + i);
GetComponent<TMP_Text>().text = _randomLetter.ToString();
}
Bengali script code:
private void OnEnable()
{
var i = UnityEngine.Random.Range(0, 16); //12 vowels in bengali but here 16 as range including non-existent values
_randomLetter = (char) ('অ' + i);
GetComponent<TMP_Text>().text = _randomLetter.ToString();
}
easiest way is to build a list of all the allowed characters, and generate a random index into this list. Note that a string can be used like a list of characters.
const string allowedCharacters = "abe";
var randomIndex = UnityEngine.Random.Range(0,allowedCharacters.Length);
var randomCharacter = allowedCharacters[randomIndex];
Another easy way is to use rejection sampling

Generate 5 length unique code from natural number

I need to generate a unique code with 5 lengths with the given number. In other words, I need to encode natural number to 5 length unique code
I wanna give fixed-length rememberable code to the customer, and keep the sequential number in the database and encode or decode when needed.
The given number can be in the range of 1 to 9999999.
But the result always must be 5 lengths.
for example
1 => a56er
or
2 => c7gh4
Uniqueness is important
I googled a lot and I can't find a solution.
The given number can be in the range of 1 to 9999999
Right. So you need to encode 24 bits of information, and you have 5 characters in which to do that - so you need 5 bits per character. That's pleasantly in the range of "only digits and lower case ASCII characters" and you can even remove points of confusion like "o/0" and "i/1".
Note that this isn't in any way "secure" - it's entirely predictable and reversible. If you don't want customers being able to reverse engineer their sequence number from the encoded form, it won't work. But it's a simple way of encoding a number as a fixed-length string.
Sample code showing encoding and decoding:
using System;
using System.Globalization;
public class Test
{
static void Main()
{
EncodeDecode(10);
EncodeDecode(100);
EncodeDecode(1000);
EncodeDecode(10000);
EncodeDecode(100000);
EncodeDecode(1000000);
EncodeDecode(9999999);
void EncodeDecode(int number)
{
string encoded = EncodeBase32(number);
int decoded = DecodeBase32(encoded);
Console.WriteLine($"{number} => {encoded} => {decoded}");
}
}
private const string Base32Alphabet =
"23456789abcdefghjklmnpqrstuvwxyz";
private static string EncodeBase32(int number)
{
// TODO: Range validation
char[] chars = new char[5];
for (int i = 0; i < 5; i++)
{
chars[i] = Base32Alphabet[number & 0x1f];
number = number >> 5;
}
return new string(chars);
}
private static int DecodeBase32(string text)
{
if (text.Length != 5)
{
throw new ArgumentException("Invalid input: wrong length");
}
int number = 0;
for (int i = 4; i >= 0; i--)
{
number = number << 5;
int index = Base32Alphabet.IndexOf(text[i]);
if (index == -1)
{
throw new ArgumentException("Invalid input: invalid character");
}
number |= index;
}
return number;
}
}
Output:
10 => c2222 => 10
100 => 65222 => 100
1000 => az222 => 1000
10000 => jsb22 => 10000
100000 => 2p352 => 100000
1000000 => 2ljy2 => 1000000
9999999 => zm7kb => 9999999
Based on your requirements, I will first answer to your question, then give you what I think is the best solution.
So, based on your number 1 to 9999999, you can use a SHA256 or MD5 or any other hashing function to generate a string, then use Substring on a random part of the string, to get the code you ask for.
A more simple approach which I personally used is to just ignore the user input, and use Guid.NewGuid() function, which will generate a random string of 16 characthers, on which you can remove the "-" and take 5 random charachters with substring and get the code you want.
Guid.NewGuid()
Gives you codes in a fashion like "a869ee3e-13b2-46ce-8c09-ff8998ab9393". Then you apply a
string.Replace("-")
and you get "a869ee3e13b246ce8c09ff8998ab9393" then you take a random piece of 5 charachters in the string (just do a substring and pass as starting point a Random number that is ranged between 1 and string lenght -5 (if you want a 5 lenght charachter).
Or to put more simple
Guid.NewGuid().ToString().Replace("-", "").Substring(x.Next(1,27),5)
This will give the code you're asking for

Checking two conditions while iterating over an array of characters

Having learned the basics/fundamentals of the C# programming language, I am now trying to tackle my first real-world problem: Write a program that, given a string, finds its longest sub-string that contains at least one upper-case letter but no digits (and then displays the length of this longest sub-string). This could be two qualifying conditions for an acceptable password, for example...
I have written the code below all by myself, which means there is probably performance issues, but that is for later consideration. I am stuck at the point where I have to make sure there is no digit in the sub-string. The comments in my code show my thinking while writing the program...
I thought first I should check to see if there is an upper-case letter in an extracted sub-string, and if there was, then I can store that qualifying sub-string in a list and then break out of the loop. But now I wonder how to check the no-digit condition at the same time in the same sub-string?
I am trying to keep it neat and simple (as I said I have only just started writing programs longer than a few lines!) so I thought doing a nested loop to check every character against !char.IsNumber(letter) might not be optimal. Or should I first check to see if there is no digit, then see if there is at least a capital character?
I feel confused how to achieve both restrictions, so I would appreciate some help in resolving this issue. I would also appreciate any observations or suggestions you might have. For example, is it OK to store my sub-strings in a list? Should I make a dictionary of some sort? Is my all-possible-sub-string extraction nested-loop optimal?
p.s. Some bits are still unfinished; for example I am still to implement the last step to find the longest sub-string and display to the user its length...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PasswordRestriction
{
class Program /// Write a program that, given a string, finds the longest substring that is a valid password and returns its length.
{
static void Main(string[] args)
{
// Ask the user for an alphanumeric string.
Console.WriteLine("Enter a string of alphanumeric values:");
// Receive the user input as string.
string password = Console.ReadLine();
// Print the length of the longest qualifying substring of the user string.
Console.WriteLine("Length of the longest qualifying substring:\n" + Solution(password).Length );
// Prevent the console window from closing.
Console.ReadLine();
}
/// The method that exracts the longest substring that is a valid password.
/// Note that a substring is a 'contiguous' segment of a string.
public static string Solution(string str)
{
// Only allow non-empty strings.
if ( String.IsNullOrEmpty(str) )
{
return "";
}
else
{
// Only allow letters and digits.
if ( str.All(char.IsLetterOrDigit) )
{
// A list for containing qualifying substrings.
List<string> passwordList = new List<string>();
// Generate all possible substrings. Note that
// string itself is not a substring of itself!
for (int i = 1; i < str.Length; i++)
{
for (int j = 0; j <= (str.Length-i); j++)
{
string subStr = str.Substring(j, i);
Console.WriteLine(subStr);
bool containsNum = false;
bool containsUpper = false;
// Convert the substrings to arrays of characters with ToCharArray.
// This method is called on a string and returns a new character array.
// You can manipulate this array in-place, which you cannot do with a string.
char[] subStrArray = subStr.ToCharArray();
// Go through every character in each substring.
// If there is at least one uppercase letter and
// no digits, put the qualifying substring in a list.
for (int k = 0; k < subStrArray.Length; k++)
{
char letter = subStrArray[k];
if ( char.IsNumber(letter) )
{
containsNum = true;
break;
}
if ( char.IsUpper(letter) )
{
containsUpper = true;
}
if ( containsUpper && (containsNum == false) && (k == subStrArray.Length - 1) )
{
Console.WriteLine("Found the above legit password!");
passwordList.Add(subStr);
}
}
}
}
//Find the longest stored string in the list.
//if (passwordList.Count != 0)
//{
string maxLength = passwordList[0];
foreach (string s in passwordList)
{
if (s.Length > maxLength.Length)
{
maxLength = s;
}
}
//}
// Return the qualifying substring.
return maxLength;
}
else
{
return "aaaaaaaaaa";
}
}
}
}
}
A good problem for Linq
contains no digits - Split on digits
at least one upper-case letter - Where + Any
longest (not shortest) OrderByDescending
longest (just one) - FirstOrDefault
Implementation
string source = ....
var result = source
.Split('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')
.Where(line => line.Any(c => c >= 'A' && c <= 'Z')) // or char.IsUpper(c)
.OrderByDescending(line => line.Length)
.FirstOrDefault(); // null if there're no such substrings at all
As an alternative to the Linq answer, and if I understand you correctly, this is what I'd do, replacing the content of the str.All condition:
string qualifier;
string tempQualifier;
bool containsUpper = false;
for (int i = 0; i < str.Length(); i++) {
tempQualifier += str[i];
if (char.IsNumber(str[i])) {
if (containsUpper) {
if (tempQualifier.Length > qualifier.Length && tempQualifier.Length != str.Length) {
qualifier = tempQualifier;
}
containsUpper = false;
}
tempQualifier = "";
} else if (char.IsUpper(str[i])) {
containsUpper = true;
}
}
return qualifier;
This would go through the string, building up the substring until it comes across a number. If the substring contains an uppercase letter and is longer than any previous qualifier, it is stored as the new qualifier (also assuming that it isn't the length of the string provided). Apologies if I've made any mistakes (I'm not well versed in C#).
It's much longer than the Linq answer, but I thought it'd be handy for you to see the process broken down so you can understand it better.

I'm trying to find a specific word within a char array

Using C# I'm trying to find a specific word within a char array. Also, I don't want the same letter used more than once i.e. the word is 'hello' and I'm trying to find it within a random array of letters, so if the letter 'l' is used out of the random array of letters, I don't want it to be used again. There should be another 'l' within the array of letters to be used as the second 'l' in "hello". Just trying to be precise. A simple answer would be very helpful. Thank you.
Here is my attempt so far.
public static char [] Note = "hello".ToCharArray();
public static char [] Newspaper = "ahrenlxlpoz".ToCharArray();
static void main(string[] args)
{
Array.Sort(Note);
Array.Sort(Newspaper);
if(Newspaper.Contains<Note>)
{
Console.Write("It should display the letters of Note found within Newspaper");
}
}
I assume by "contains" you mean Newspaper has enough number of letters from each letter to make up Note. For example, you need at least two l's to make up the word "hello". If so, you need to basically count the number of each letter in both strings, and make sure the number of each letter in Note is less than or equal to the number of that letter in Newspaper.
var dictNote = Note.GroupBy(c => c).ToDictionary(g => g.Key, g => g.Count());
var dictNews = Newspaper.GroupBy(c => c).ToDictionary(g => g.Key, g => g.Count());
bool contains = dictNote.All(x =>
dictNews.ContainsKey(x.Key) && x.Value <= dictNews[x.Key]);
In fact, a string is a char array. And the most "classic" way to do this would be:
string Note = "hello";
char[] Newspaper = "ahrenlxlpoz".ToCharArray();
string res = "";
for (int i = 0; i < Note.Length; i++)
for (int j = 0; j < Newspaper.Length; j++)
if (Note[i] == Newspaper[j])
{
res += Newspaper[j];
Newspaper[j] = ' ';
break;
}
//This prints the remaining characters in Newspaper. I avoid repeating chars.
for (int i = 0; i < Newspaper.Length; i++ )
Console.Write(Newspaper[i]+"\n");
Console.Write("\n\n");
if (Note.Equals(res)) Console.Write("Word found");
else Console.Write("Word NOT found");
Console.Read();
At the end, res will be "hello". Print res in the console. I added the ' ' to avoid repeated characters as someone said in the answer up. So at the end it will compare the result with the word and will tell you if it found the word in the string. Try changing Newspaper to this: "ahrenlxlpaz" and it will tell you the word is NOT found :)
Try this:
public static char[] Note = "hello".ToCharArray();
public static char[] Newspaper = "ahrenlxlpoz".ToCharArray();
foreach (char c in Note) //check each character of Note
{
if (Newspaper.Contains(c))
{
Console.Write(c); //it will display hello
}
}

Get the letters (ABCDE) between two letters (AE) using C#

I need to get the letters as an array on passing two letters using C#
For ex.: When i pass "AE", i need to get the {A,B,C,D,E} as an array. and passing "FJ" should return {F,G,H,I,J}.
The Enumerable class can create a range, which makes the looping simple:
public static char[] CharactersBetween(char start, char end) {
return Enumerable.Range(start, end - start + 1).Select(c => (char)c).ToArray();
}
Note: A char value converts implicitly into int, so there is no conversion needed in that direction. You only have to convert the integers back to char.
Edit:
If you want to send in the alphabet to use (to handle language differences), you can use Substring to get a part of that string:
public static char[] CharactersBetween(char start, char end, string alphabet) {
int idx = alphabet.IndexOf(start);
return alphabet.Substring(idx, alphabet.IndexOf(end) - idx + 1).ToCharArray();
}
Do you mean something like
char[] CharactersBetween(char start, char end)
{
List<char> result = new List<char>();
for (char i = start; i <= end; i++)
{
result.Add(i);
}
return result.ToArray();
}
This should work out well
string startandend = "AG";
string result= "";
for( char i = startandend[0]; i <= startandend[1]; i++){
result += i;
}
result will now contain ABCDEFG.
You should probably add some logic to check if startandend actually have a Length of 2 and so on, but this should be a good starting block for you.
If you want the char[] instead of the string representation, simply call result.ToCharArray() at the end.
Use a loop with integer conversion
with
System.Convert.ToInt32(Char);
and
System.Convert.ToChar(Int32);
see http://msdn.microsoft.com/en-us/library/system.convert_methods.aspx
Pretty simple if you use a fixed alphabet,
public static string ALPHABET = "ABCDEFGHIJKLMNOPWRSTUVWXYZ";
public static List<char> GetLetters(string firstLast)
{
List<char> letters = new List<char>();
int start = ALPHABET.IndexOf(firstLast[0]);
int end = ALPHABET.IndexOf(firstLast[1]);
for (int i = start; i <= end; i++)
{
letters.Add(ALPHABET[i]);
}
return letters;
}
Obviously add in your checks for various things, but it does the basic job.
You're going to have to reference whichever alphabet you want to use. English is easy enough as the letters happen to correspond to code-point order, French treats Œ and Æ as letters in their own right sometimes, and not others. Danish and Norwegian place "Æ, Ø, Å" after Z and Swedish does the same with "Å, Ä, Ö". Irish uses "ABCDEFGHILMNOPRSTU" as the alphabet, but does also use J, K, Q, V, W, X, Y & Z in loan words.
And those are relatively easy cases. So there's no one-size-fits-all.
The easiest way to pass an alphabet is to have a string that contains it. So, e.g. the Danish alphabet would have the string "ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ" while French could either include the ligatures or not as you wish (but do you need to deal with the possibility of receiving them while not using them?).
This done:
public static IEnumerable<char> AlphabetRange(string alphabet, string alphaRange)
{
if(alphaRange == null)
throw new ArgumentNullException();
if(alphaRange.Length < 2)
throw new ArgumentException();
int startIdx = alphabet.IndexOf(alphaRange[0]);
int endIdx = alphabet.IndexOf(alphaRange[1]) + 1;
if(startIdx == -1 || endIdx == 0)
throw new ArgumentException();
while(startIdx < endIdx)
yield return alphabet[startIdx++];
}

Categories

Resources