How to Fix an array and a loop? - c#

I created a User login and password program where a user has to type in a username and a password. I have my usernames and passwords in parallel arrays. If a user types the username or password wrong for the first time they get a message saying "Username is incorrect try again" or "password is incorrect try again".
My problem is if the user types in the wrong username for the first time they get the error message, but if the user type in the right username for the second time they still get the error message.
What I found out is when they get it wrong for the first time the program asks them to input the second username instead of the first one. How can I fix this so the program lets the user type in the first username instead of asking for the second username?
// The available usernames and passwords a user can input
string[] username = {"BUL","GVL","UDF","RFT","WDR" };
int[] password = {100, 200, 300, 400, 500 };
Console.WriteLine("\nUsername,Password \nBUL,100 \nGVL,200 \nUDF,300 \nRFT,400 \nWDR,500 ");
// Loop for Username Input
for (int i = 0; i < username.Length; i++)
{
Console.WriteLine("Enter Username");
string inputUsername = Console.ReadLine();
// if user type a wrong username, they need to try again
if (username[i] != inputUsername)
{
Console.WriteLine("Incorrect Username, Try again");
}
else
break;
}

How about using a Dictionary to store the usernames and passwords as Key-Value-Pairs instead of storing theme in two separate arrays? This way, you can check both username and password in one step.
Dictionary<string, string> dic = new Dictionary<string, string>
{
{ "BUL", "100" },
{ "GVL", "200" },
{ "UDF", "300" },
{ "RFT", "400" },
{ "WDR", "500" }
};
while(true)
{
Console.WriteLine("Enter Username");
string inputUsername = Console.ReadLine();
Console.WriteLine("Enter Password");
string pass = Console.ReadLine();
if (!dic.Contains(new KeyValuePair<string, string>(inputUsername, pass)))
Console.WriteLine("Incorrect Username/password, Try again");
else break;
}

Try this:
bool isUserNameValid = false;
string inputUsername = "";
do
{
Console.WriteLine("Enter Username");
inputUsername = Console.ReadLine();
for ( int i = 0; i < username.Length; i++ )
if ( username[i] == inputUsername )
{
isUserNameValid = true;
break;
}
if ( !isUserNameValid )
Console.WriteLine("Incorrect Username, Try again");
}
while ( !isUserNameValid );
bool isPasswordValid = false;
int inputPassword = 0;
do
{
Console.WriteLine("Enter Password");
int.TryParse(Console.ReadLine(), out inputPassword);
for ( int i = 0; i < password.Length; i++ )
if ( password[i] == inputPassword )
{
isPasswordValid = true;
break;
}
if ( !isPasswordValid )
Console.WriteLine("Incorrect Password, Try again");
}
while ( !isPasswordValid );

If you want to persist using Array, then you could do as the following code. But it would be always better to use Dictionaries in this scenario, which provides you a mapping between UserName and Password. If you were to use Arrays, you would need to map them yourself based on Array Index.
You can employ two loops, each validating the username and then combination of username/password until it is valid.
string inputUserName,inputPassword;
// Loop for Username Input
while(true)
{
Console.WriteLine("Enter Username");
inputUserName = Console.ReadLine();
if(username.Contains(inputUserName))
break;
else
Console.WriteLine("Incorrect UserName");
}
while(true)
{
Console.WriteLine("Enter Password");
inputPassword = Console.ReadLine();
var indexOfUserName = Array.IndexOf(username,inputUserName);
if(Int32.TryParse(inputPassword,out var value) && password[indexOfUserName] == value)
break;
else
Console.WriteLine("Incorrect Password");
}
While using Dictionary you could change the code as follows.
// Dictionary declaration
var userDictionary = new Dictionary<string,int>
{
{ "BUL", 100 },
{ "GVL", 200 },
{ "UDF", 300 },
{ "RFT", 400 },
{ "WDR", 500 }
};
string inputUserName,inputPassword;
// Loop for Username Input
while(true)
{
Console.WriteLine("Enter Username");
inputUserName = Console.ReadLine();
if(userDictionary.Keys.Contains(inputUserName))
break;
else
Console.WriteLine("Incorrect UserName");
}
while(true)
{
Console.WriteLine("Enter Password");
inputPassword = Console.ReadLine();
if(Int32.TryParse(inputPassword,out var value) && userDictionary[inputUserName] == value)
break;
else
Console.WriteLine("Incorrect UserName");
}
If you would like to further eliminate some duplicate code, you could refactor the code as following.
var userDictionary = new Dictionary<string,int>
{
{ "BUL", 100 },
{ "GVL", 200 },
{ "UDF", 300 },
{ "RFT", 400 },
{ "WDR", 500 }
};
Console.WriteLine("\nUsername,Password \nBUL,100 \nGVL,200 \nUDF,300 \nRFT,400 \nWDR,500 ");
var userName = ReadFromUserTillTrue("Enter UserName","Incorrect UserName",x=>userDictionary.Keys.Contains(x));
var password = ReadFromUserTillTrue("Enter Password","Incorrect Password",x=>Int32.TryParse(x,out var value) && userDictionary[userName]== value);
Where ReadFromUserTillTrueis defined as
public string ReadFromUserTillTrue(string promptMessage,string errorMessage,Func<string,bool> validator)
{
var input = string.Empty;
while(true)
{
Console.WriteLine(promptMessage);
input = Console.ReadLine();
if(validator(input))
break;
else
Console.WriteLine(errorMessage);
}
return input;
}

Besides realy great answers in this thread, I'd also recommend to check Polly.NET framework. When I need to do something with retries I find it already has something that serves my needs. Below is an example of how you can implement retries with countdown (and there is many more other nice things in the framework):
var usernames = new List<string>(){ "BUL", "GVL", "UDF", "RFT", "WDR" };
int[] passwords = { 100, 200, 300, 400, 500 };
var user = Policy
.HandleResult<String>(r => !usernames.Contains(r))
.RetryForever((r)=> Console.WriteLine($"Username is incorrect, Try again"))
.Execute(() => {
Console.WriteLine("Enter Username:");
return Console.ReadLine();
});
var expectedPassword = passwords[usernames.IndexOf(user)];
var maxRetries = 5;
Policy
.HandleResult<int>(r => r != expectedPassword)
.Retry(maxRetries, (r, i) => Console.WriteLine($"Password is incorrect. Retries left: {maxRetries - i + 1}"))
.Execute(() => {
Console.WriteLine("Enter Password:");
// should here also be a retry? try do that with Polly :)
int.TryParse(Console.ReadLine(), out var password);
return password;
});

Related

C#, Validating user input for letters and whitespace using boolean

I'm making a program that reverses a string and doesn't allow for anything else than letters and whitespaces, problem is that if i enter a non-valid input and then try to input a valid input it just keeps printing error. I think the problem has something to do with my while loop and the bool result, but i can't figure it out. Please help and thank you!
static void Reverse()
{
string name;
Console.Write("Enter your name: ");
name = Console.ReadLine();
bool result = name.All(c => char.IsWhiteSpace(c) || char.IsLetter(c));
if (Regex.IsMatch(name, #"^[a-zA-Z- ]+$")) // Validates the input for characters and/or spaces
{
char[] charArr = name.ToCharArray();
Array.Reverse(charArr);
string nameRev = new string(charArr);
Console.WriteLine("String is {0}", nameRev);
}
else
{
while (name == String.Empty || result == false) //Should validate the input for whitespace or letter if it doesn't pass the first validation
{
Console.Write("Error! Enter your name, only letters allowed: ");
name = Console.ReadLine();
}
}
You need to wrap your while loop around the hole sequence instead of just having it inside the else statement.
Example:
static void Reverse()
{
// Continues executing as long as result stays false.
bool result;
do
{
string name;
Console.Write("Enter your name: ");
name = Console.ReadLine();
result = name.All(c => char.IsWhiteSpace(c) || char.IsLetter(c));
if (Regex.IsMatch(name, #"^[a-zA-Z- ]+$"))
{
char[] charArr = name.ToCharArray();
Array.Reverse(charArr);
string nameRev = new string(charArr);
Console.WriteLine("String is {0}", nameRev);
}
else
{
Console.WriteLine("Error! Only letters allowed");
}
}
while (!result);
}

How to repeat until the correct information is provided in c#?

I am currently writing a program where I have to
1) Giving user some options: 1.Search by name? 2. Search by date of birth?
2) If user selects search by name, ask them to put first name and then give the output
3) If user selects search by date of birth, ask them to put date of birth with format (MM/DD/YYYY) and then give the output.
I have to Repeat the options if the validation failed or couldn’t find the data.
I am struggling with the concept of repeating the options. ANy help is extremely appreciated.
My code so far
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Week2Tutorial
{
class Program
class Student
{
public int Id { get; set; }
public string FirstName { get; set; }
public string Lastname { get; set; }
public DateTime DOB { get; set; }
public string Gender { get; set; }
}
static void Main(string[] args)
{
var students = new List<Student>()
{
new Student() { Id = 1,FirstName = "Min Chul",Lastname = "Shin",DOB = new DateTime(2010,01,01),Gender = "Male"},
new Student() { Id = 2,FirstName = "Nicky", Lastname = "Lauren", DOB = new DateTime(2009, 01, 01), Gender = "Female"},
new Student() { Id = 3, FirstName = "Amy", Lastname = "Park", DOB = new DateTime(2008, 01, 01), Gender = "Female" },
new Student() { Id = 4, FirstName = "Aurelie", Lastname = "Adair", DOB = new DateTime(2007, 01, 01), Gender = "Female" }
};
//foreach (var x in students)
//{
// Console.WriteLine("Id = {0}, FirstName = {1}, Lastname = {2}, DOB = {3}, Gender = {4}",x.Id,x.FirstName,x.Lastname,x.DOB,x.Gender);
//}
Console.WriteLine(" Please Choose one of the options:");
Console.WriteLine("1> Search by first name");
Console.WriteLine("2> Search by date of birth");
switch ( Convert.ToInt32(Console.ReadLine()))
{
case 1:
Console.WriteLine("You choose:1");
Console.WriteLine("Type your first name:");
var a = Console.ReadLine();
var case1 = students.Where(x=>x.FirstName==a);
if (case1.Count()!=0)
{
Console.WriteLine("Found! Here are the details:");
foreach (var x in case1)
{
Console.WriteLine("Name: {0}{1} D.O.B:{2} and Gender{3}", x.FirstName, x.Lastname, x.DOB, x.Gender);
}
}
else
{
Console.WriteLine(" Enter the correct information");
}
break;
case 2:
Console.WriteLine("You choose:2");
Console.WriteLine("Enter your Date of Birth in format MM/DD/YYYY:");
var b = DateTime.Parse(Console.ReadLine());
//Console.WriteLine(b);
//Console.ReadLine();
var case2 = students.Where(x => x.DOB == b);
if (case2.Count() != 0)
{
Console.WriteLine("Found! Here are your details");
foreach (var x in case2)
{
Console.WriteLine("Name:{0} {1} DOB:{2} Gender:{3}", x.FirstName, x.Lastname, x.DOB, x.Gender);
}
}
else
{
Console.WriteLine(" Enter the correct information");
}
break;
default:
Console.WriteLine("Please enter the valid option");
break;
}
}
}
}
It can be Done be with do while loop here is the general syntax of do while Loop
do {
code to be executed;
} while (condition is true);
what is do while loop it is an endless loop that is executes the code till the condition is true.
In Your Case we are taking a new varibale temp which is intially zero means no
result if any of your switch case gets true and find results according to user's search query the count of that result will be copied to temp variable now temp no longer have zero value means condition is false means the code will not be executed again
You Just Need to start an endless loop till the condition is true
do{
var temp=0; ///Temporary variable to check the result count
//intially variable b will be zero because INtially result count is zero
Console.WriteLine(" Please Choose one of the options:");
Console.WriteLine("1> Search by first name");
Console.WriteLine("2> Search by date of birth");
switch ( Convert.ToInt32(Console.ReadLine()))
{
case 1:
Console.WriteLine("You choose:1");
Console.WriteLine("Type your first name:");
var a = Console.ReadLine();
var case1 = students.Where(x=>x.FirstName==a);
temp=case1.Count(); //Getting result count in another variable
if (case1.Count()!=0)
{
Console.WriteLine("Found! Here are the details:");
foreach (var x in case1)
{
Console.WriteLine("Name: {0}{1} D.O.B:{2} and Gender{3}", x.FirstName, x.Lastname, x.DOB, x.Gender);
}
}
else
{
Console.WriteLine(" Enter the correct information");
}
break;
case 2:
Console.WriteLine("You choose:2");
Console.WriteLine("Enter your Date of Birth in format MM/DD/YYYY:");
var b = DateTime.Parse(Console.ReadLine());
//Console.WriteLine(b);
//Console.ReadLine();
var case2 = students.Where(x => x.DOB == b);
temp=case2.Count(); //Getting result count in another variable
if (case2.Count() != 0)
{
Console.WriteLine("Found! Here are your details");
foreach (var x in case2)
{
Console.WriteLine("Name:{0} {1} DOB:{2} Gender:{3}", x.FirstName, x.Lastname, x.DOB, x.Gender);
}
}
else
{
Console.WriteLine(" Enter the correct information");
}
break;
default:
Console.WriteLine("Please enter the valid option");
break;
}
}while(temp==0); ////Endless Loop while result is zero
intially temp is equal to zero means result count is zero
so it will again intiate the loop However if there is any result
that means temp is not equal to zero it will not execute the code
Just use while loop.
Example from: https://www.dotnetperls.com/console-readline
using System;
class Program
{
static void Main()
{
while (true) // Loop indefinitely
{
Console.WriteLine("Enter input:"); // Prompt
string line = Console.ReadLine(); // Get string from user
if (line == "exit") // Check string
{
break;
}
Console.Write("You typed "); // Report output
Console.Write(line.Length);
Console.WriteLine(" character(s)");
}
}
}

using do while statement in method returning string

I am writing a program for shopping system. In this I am using array to get input from the brand name from the user. I am using method which returns string to get the input. Following is code:
public class Brand{
private string brandName;
public string BrandName
{
get { return brandName; }
set { brandName = value; }
}
public string getBrandName()
{
string[] brands = new string[5];
brands[0] = "Honda";
brands[1] = "Suzuki";
brands[2] = "Ferrari";
brands[3] = "BMW";
brands[4] = "Toyota";
Console.WriteLine("Please enter the brand name from the above given brands..");
string temp = Console.ReadLine();
do
{
try
{
for (int i = 0; i < 6; i++)
{
if (brands[i].Contains(temp))
{
this.BrandName = temp;
break;
}
}
return this.BrandName;
}
catch
{
Console.WriteLine("Your provide brand does not match with the database in our system. Please try another one.");
}
} while (BrandName!=temp);
}
}
The problem is that I am at beginner level and not getting the trick what should be in this while statement that it loops and asks user to input again and again until he enters the correct brand name. Please help me.
Maybe this will work based on your code:
public string getBrandName()
{
string[] brands = new string[5];
brands[0] = "Honda";
brands[1] = "Suzuki";
brands[2] = "Ferrari";
brands[3] = "BMW";
brands[4] = "Toyota";
Console.WriteLine("Please enter the brand name from the above given brands..");
string temp = Console.ReadLine();
while(!brand.Contains(temp))
{
Console.WriteLine("Your provide brand does not match with the database in our system. Please try another one.");
temp = Console.ReadLine();
}
return temp;
}
Few things to notice:
We will ask the user for a brand name.
We will check that the input is a brand from brands list (you use contains to check if the input is in the char array of every brand name, watch the difference).
If then name is in the list we will not enter inside the loop and we
will return the brand name.
If the name is not in the list we will ask the user again to insert a
valid brand name until he will enter any and then we will return it.
if you have only 4 no of brands then you can try or statement for all of them in while loop
while (input== 'brand1'||'brand2')
or if your list is too big then you can put them in an arraylist
like this
List <String> listClone = new ArrayList<String>();
for (String string : list) {
if(string.matches("(?i)(bea).*")){
listClone.add(string);
}
}
System.out.println(listClone);
You have an outOfRange exception here :
for (int i = 0; i < 6; i++)
beacuse there is out of range from the array where brands[5].
The function contains return true or false when the input string is substring of the specified string and not equel !!!
You arrive to this row only if has exception:
Console.WriteLine("Your provide brand does not match with the database in our system. Please try another one.");
Check the following code - it work well :
class Program
{
static void Main(string[] args)
{
Brand brand = new Brand();
string brandName = brand.getBrandName();
Console.WriteLine("You enter correct brand name !!!");
Console.WriteLine(brandName);
Console.ReadLine();
}
public class Brand
{
private string brandName;
public string BrandName
{
get { return brandName; }
set { brandName = value; }
}
public string getBrandName()
{
bool isValid = false;
string temp = "";
string[] brands = new string[5];
brands[0] = "Honda";
brands[1] = "Suzuki";
brands[2] = "Ferrari";
brands[3] = "BMW";
brands[4] = "Toyota";
Console.WriteLine("Please enter the brand name from the above given brands..");
while (!isValid)
{
for (int i = 0; i < brands.Length; i++)
{
Console.WriteLine(brands[i]);
}
temp = Console.ReadLine();
for (int i = 0; i < brands.Length; i++)
{
if (brands[i] == temp)
{
this.BrandName = temp;
isValid = true;
break;
}
else
{
isValid = false;
}
if (i == brands.Length - 1)
{
Console.WriteLine("Your provide brand does not match with the database in our system. Please try another one.");
}
}
}
return temp;
}
}
}

How do I make c# ignore letter case

Here I have some simple C# code;
Console.WriteLine("Enter Name");
var name = Console.ReadLine();
if (name == "ashley")
{
Console.WriteLine("You entered: " + name);
}
Console.Read();`
If the user enters ashley it will display "You entered ashley". However if the user enters Ashley or AsHlEy it won't work. What do I need to add to this or how to format so it will ignore the case?
Use string.Equals with an appropriate StringComparison
if (string.Equals(name, "ashley", StringComparison.CurrentCultureIgnoreCase))
{
...
}
If you know that the variable is not null you can also use
if (name.Equals("ashley", StringComparison.CurrentCultureIgnoreCase))
{
...
}
To answer your question in the comments, a do-while loop can be used to loop until the question is answered correctly. The below will loop until the user enters something other than ashley.
string name;
do
{
Console.WriteLine("Enter Name");
name = Console.ReadLine();
}
while (string.Equals(name, "ashley", StringComparison.CurrentCultureIgnoreCase));
You could combine this with a guard variable if you want different messaging:
string name;
bool nameIsCorrect = false;
do
{
Console.WriteLine("Enter Name");
name = Console.ReadLine();
nameIsAshley = string.Equals(name, "ashley", StringComparison.CurrentCultureIgnoreCase);
if (nameIsAshley)
{
Console.WriteLine("Stop entering 'ashley'");
}
}
while (!nameIsAshley);
String.Compare takes a boolean parameter which allows you to ignore casing during comparison:
Console.WriteLine("Enter Name");
var name = Console.ReadLine();
if (String.Compare(name, "ashley", true) == 0)
{
Console.WriteLine("You entered: " + name);
}
Console.Read();
change this:
if (name == "ashley")
to this:
if (name.ToLower() == "ashley")
Use ToLower like this:
Console.WriteLine("Enter Name");
var name = Console.ReadLine();
if (name.ToLower() == "ashley")
{
Console.WriteLine("You entered: " + name);
}
Console.Read();`
You can use the String.ToLower method
your test would be: if (name.ToLower() == "ashley")

Object Arrays in Console Application

I want to create an array of users in a console app but cant seem to get it right, can anyone please help, here is my code.
class Program
{
static void InputUser(User U)
{
Console.WriteLine("Please enter a User:");
Console.WriteLine("User ID:");
U.ID = int.Parse(Console.ReadLine());
Console.WriteLine("Titel:");
U.Titel = Console.ReadLine();
Console.WriteLine("Name:");
U.Name = Console.ReadLine();
Console.WriteLine("Surname:");
U.Surname = Console.ReadLine();
Console.WriteLine("Telephone Number:");
U.Telephone = int.Parse(Console.ReadLine());
Console.WriteLine();
}
static void Main()
{
User[] users = new User[2]
{
InputUser(new User);
}
}
}
First, change the InputUser method to return a User object which will be constructed using the user's input:
static User InputUser()
{
User U = new User();
Console.WriteLine("Please enter a User:");
Console.WriteLine("User ID:");
U.ID = int.Parse(Console.ReadLine());
Console.WriteLine("Titel:");
U.Titel = Console.ReadLine();
Console.WriteLine("Name:");
U.Name = Console.ReadLine();
Console.WriteLine("Surname:");
U.Surname = Console.ReadLine();
Console.WriteLine("Telephone Number:");
U.Telephone = int.Parse(Console.ReadLine());
Console.WriteLine();
return U;
}
And then call the InputUser method two times, since you're initializing an array of User objects with the size of 2:
static void Main()
{
User[] users = new User[2]
{
InputUser(),
InputUser()
}
}
Change your main method to something like:
static void Main()
{
User[] users = new User[2];
for (int i=0;i<users.Length; i++)
{
users[i] = new User();
InputUser(users[i]);
}
}
User[] users = new User[2]
will just create an array of User, but it doesnt initialize them.
For each of them you need to create a User.
So add a loop after it like this:
for (int i=0;i<users.Length; i++)
{
users[i] = InputUser(users[i]);
}
InputUser needs to pass the User object by reference (ref keyword) or it needs to return a new instance of User instead of accepting a parameter.

Categories