First things first, I am an absolute beginner to c# so excuse me for any dumb mistakes I have done.
currently, I am making a "banking system" as my beginner project. I am getting a frustrating error
with entering a key.
var input = Convert.ToString(Console.ReadKey());
if (input == "E") {
Console.WriteLine("English has been selected");
}
if (input == "A")
{
Console.WriteLine("تم اختيار اللغة العربية");
}
else {
Console.WriteLine("Error!");
}
if I input E or A the console only displays the Else condition instead of the two if conditions. side note: vscode doesn't show any errors relating to this.
In your code you are using ReadKey() - but you must be sure to use it properly. It's not quite as simple as say Python input() but C#'s ReadKey() does a good job once you understand it.
First, and most importantly, you need to know that ReadKey() does not just return a letter (like 'a', or 'b'), and it does not even return a numeric key code (like 9 or 10). Instead, it returns something called a ConsoleKeyInfo. Technically, it is a struct, but you can just think of it as "information about the key pressed".
Second, because your goal is to know what key was pressed and specifically if it was an A or E, you can get the Key property from the ConsoleKeyInfo. But once again, we are not getting a letter (like 'a' or 'b'), or strictly speaking an integer (like 9 or 10) - . The Key we get is an Enum or more specifically a ConsoleKey Enum. So at this point we can either check the enum value directly, or convert it to a string representation and check it against a string value (such as "A" or "E").
Now, all of this can seem overkill for a tiny little program - but overall it provides a lot of benefit for writing safe and reliable programs. To compare it with something similar, it is like using a FileInfo object to represent a file, rather than just a using string for a filepath. But I do encourage you to read the docs referenced below because when you understand how to make use of documentation (and debugging tools) you have what you need to figure out most of this on your own!
tldr;
ReadKey() returns ConsoleKeyInfo struct, which we can use to get a Key property. Since the Key property returns an Enum, not a character or a string, we either check the value of the enum directly, or take one more step of calling ToString() on the ConsoleKeyEnum to convert it to a "letter" or "key" in string form. Additionally, the ConsoleKeyInfo class exposes a KeyChar property that may be used instead.
Reference: https://learn.microsoft.com/en-us/dotnet/api/system.console.readkey?view=net-6.0
sample revised code
var input = Console.ReadKey();
if (input.Key.ToString() == "E")
{
Console.WriteLine("English has been selected");
}
else if (input.Key.ToString() == "A")
{
Console.WriteLine("تم اختيار اللغة العربية");
}
else
{
Console.WriteLine("Error!");
}
Because we are working with Enums, it is really simpler and safest to use them in the comparisons directly:
var input = Console.ReadKey();
if (input.Key == ConsoleKey.E)
{
Console.WriteLine("English has been selected");
}
else if (input.Key == ConsoleKey.A)
{
Console.WriteLine("تم اختيار اللغة العربية");
}
else
{
Console.WriteLine("Error!");
}
Additionally we have the option to use the KeyChar property (this one does, however, return characters, not strings, and case matters - so we can get 'A', or 'a' depending on if shift is used or not).
var input = Console.ReadKey();
if (input.KeyChar == 'E' || input.KeyChar == 'e')
{
Console.WriteLine("English has been selected");
}
else if (input.KeyChar == 'A' || input.KeyChar == 'a')
{
Console.WriteLine("تم اختيار اللغة العربية");
}
else
{
Console.WriteLine("Error!");
}
The simplest solution is to simply use Console.ReadLine() instead of Console.ReadKey(). This will require the user to press enter after they have selected wither A or E but this is more user friendly when selecting an option as it gives you the chance to confirm your choice.
var input = Convert.ToString(Console.ReadLine());
if (string.Equals(input, "E", StringComparison.InvariantCultureIgnoreCase))
{
Console.WriteLine("English has been selected");
}
else if (string.Equals(input, "A", StringComparison.InvariantCultureIgnoreCase))
{
Console.WriteLine("تم اختيار اللغة العربية");
}
else
{
Console.WriteLine("Error!");
}
I also added a invariant string check to ignore case (so that "a" and "A" would both be accepted for example) and added a else to the second if statement as general improvements.
Note: Your use of Console.ReadKey() didn't work because it returns a struct that holds information about the input key - this struct will not convert into the original input key if you call Convert.ToString() on it.
If you do really prefer to use Console.ReadKey() then just access the input character using Console.ReadKey().KeyChar.
var input = Convert.ToString(Console.ReadKey().KeyChar);
if (string.Equals(input, "E", StringComparison.InvariantCultureIgnoreCase))
{
Console.WriteLine("English has been selected");
}
else if (string.Equals(input, "A", StringComparison.InvariantCultureIgnoreCase))
{
Console.WriteLine("تم اختيار اللغة العربية");
}
else
{
Console.WriteLine("Error!");
}
Try this please:
using System;
class Program
{
public static void Main (string[] args)
{
string input = Console.ReadLine();
if (input == "E")
{
Console.WriteLine("English has been selected");
}
else if (input == "A")
{
Console.WriteLine("تم اختيار اللغة العربية");
}
else
{
Console.WriteLine("Error!");
}
}
}
Related
I am new to C# (1 week in) and I have been scratching my head with no answers. Simply put this is part of a text based game out of much larger file. The player has the option to accept or decline an incoming call. If y/Y or n/N is entered all is well. If I purposely enter an incorrect character the while loop will print "Please respond with 'Y' or 'N' only.." 3 times. I cannot work out why. If you enter 2 letters such as GG it will print it 4 times, 3 letters, 5 times and so on. I know this is an easy fix, I just need someone to point out what I've done wrong.
//INCOMING CALL
static void IncomingCall(char rawResponse)
{
// Convert response to upper
// (note method as ToUpper cannot be called conventionally on type char)
char response = char.ToUpper(rawResponse);
while (response != 'Y' && response != 'N')
{
WriteLine("Please respond with 'Y' or 'N' only..");
rawResponse = (char)Read();
response = char.ToUpper(rawResponse);
}
}
//called in main elsewhere in the file..
WriteLine("Incoming call from Tony. Press 'Y' to accept or 'N' to decline.");
char getInput = (char)Read();
IncomingCall(getInput);
I solved it, with your help by changing method to accept string and use ReadLine()
Changed
(response != 'Y' && response != 'N')
To
(response != "Y" && response != "N")
I did not realise '' and "" produce different results. I am used to Python. Thanks for the input guys.
I suggest changing the design. Let's implement ReadBool methods which incapsulates all the logic of bool value input:
public static bool ReadBool(string title) {
// We keep asking user until valid (N or Y) value is entered
while (true) {
// If we have a title, let's show it
if (!string.IsNullOrWhiteSpace(title))
Console.WriteLine(title);
// User has to press 'Y' or 'N'; no need for enter
var key = Console.ReadKey();
if (key.KeyChar == 'Y')
return true;
if (key.KeyChar == 'N')
return false;
// Invalid value; let user know it and try again
Console.WriteLine("Please respond with 'Y' or 'N' only..");
}
}
Possible usage:
bool acceptTony = ReadBool("Incoming call from Tony. Press 'Y' to accept or 'N' to decline.");
if (acceptTony) {
Console.WriteLine("Hi Tony!");
//TODO: put relevant code here
}
else {
Console.WriteLine("Declined");
//TODO: put relevant code here
}
Swap Read() with Console.Readline()[0];.
EDIT: Or change your method signature to be a string and leverage Console.Readline() as stated in the comments prior.
I have this if statement:
if (input == 'day')
Console.Write({0}, dayData);
When the user types 'day' it should be so that the console writes the data in that array. It works fine but is there anyway to get it to work if the user types 'DaY' or 'dAy' etc. I know I could do:
if (input == 'day' || input == 'dAy' || input == 'DaY')
Console.WriteLine({0}, dayData);
But is there anyway to make it shorter and tidier?
Thanks.
The string.Equals method allow you to set up configuration on the comparison and you can set it up to ignore case.
if (string.Equals(input, "day", StringComparison.InvariantCultureIgnoreCase))
if (input.ToLower() == "day") { }
If your code is international, you are writing a library, you want a small speed boost, you are doing this in a loop or with large strings, et cetera, use the following:
if (input.Equals("day", StringComparison.OrdinalIgnoreCase)) { }
Or to use a specific international culture:
if (string.Compare(input, "day", true, new CultureInfo("de-DE")) == 0) { }
The string.Equals method allow you could to check the content of the string and ignore the case, for sample:
if (input.Equals("day", StringComparison.OrdinalIgnoreCase))
{
}
You mention an array so I'll assume you're entering multiple things simultaneously (like 'day', 'dAy', etc)
foreach (var item in input)
{
if (item.ToLower() == "day")
{
Console.WriteLine("{0}", item);
break;
}
}
edit: this would check each item in the array, write to the console, then stop if one was "day".
Another way is
if(str1.Equals(str2, StringComparison.InvariantCultureIgnoreCase))
{
//...
}
Second parameter allow you use one of six predefined comparison modes.
i'm having trouble creating a loop that will request user input and if the input is not "Y" or "N" to re-prompt the user to input over and over until they give the correct input.
while (quitOrContinue != "Y"|"N")//cant use "Y"/"N" in the same line, how do I phrase this line?
Console.Write("\nWould you like to process another set of bowling scores?");
Console.WriteLine("\nPress 'Y' to process another set or 'N' to exit the program");
Console.Clear();// this needs to happen if the input to run again is "Y"
Well, for starters, you're not actually taking any input at all from the user. You can use Console.WriteLine to output whatever sort of instructions you want from the user, but you have to actually capture them somehow.
To get input, you'd have to use Console.Read(), and you'd have to use conditional blocks to check their input. You should wrap your code in a while loop that references a sentinel value:
bool userIsDone = false;
Console.Write("\nWould you like to process...");
while (!userIsDone)
{
string userInput = Console.ReadLine();
// ...
if (userInput == "Y")
{
// process another set here
Console.WriteLine("\nWould you like to process...");
}
else if (userInput == "N")
{
// exit your program
}
else
{
Console.WriteLine("That input is invalid.");
}
}
Also, about the code you have above - you should wrap the elements inside loops in { }, and the | is the bitwise OR, not logical or. Logical or (which I'm 99% you want in this situation) is ||, and logical and is &&.
Why not use a loop ?
string input = null;
while((input = Console.ReadLine()) != "Y" || input != "N")
{
Console.WriteLine("Invalid value, please try again:");
}
Here the expression (input = Console.ReadLine()) != "Y" || input != "N" will be evaluated before and each time after the loop runs. It basically reads a line from the input stream and assign it to input variable then checks if it's not Y or N it executes the loop body and evaluates the expression again and ask for input until the condition satisfies.You can use Console.Read method to read one charachter but it returns int so you need to cast it to char.
I have trouble implementing the Y/N or y/n in the loop. I've designed it in a way that a user can use both the capital and small letters of the Y and N for their answer in a loop. by the way here's my code but can't seem to make it work:
do
{
Console.WriteLine("\nSelect additional topping/s\n");
Console.WriteLine("1 - Extra meat: 200");
Console.WriteLine("2 - Extra cheese: 100");
Console.WriteLine("3 - Extra veggies: 80\n");
int selectedTopping = Convert.ToInt32(Console.ReadLine());
switch (selectedTopping)
{
case 1:
pizza = new MeatToppings(pizza);
break;
case 2:
pizza = new CheeseToppings(pizza);
break;
case 3:
pizza = new VeggieToppings(pizza);
break;
default:
break;
}
Console.WriteLine("\nAdd more toppings? Y/N");
}
while ((Console.ReadLine() == "Y") || (Console.ReadLine() == "y"));
while ((Console.ReadLine() == "Y") || (Console.ReadLine() == "y"));
This is going to read 2 different lines since you're calling ReadLine() twice. You need to call it once and save the value.
You can use ToUpper
while ((Console.ReadLine().ToUpper() == "Y") );
Try to use String.Equals and StringComparison:
String.Equals(Console.ReadLine(), "y", StringComparison.CurrentCultureIgnoreCase);
from MSDN:
CurrentCultureIgnoreCase: Compare strings using culture-sensitive sort rules, the current culture, and ignoring the case of the strings being compared.
OrdinalIgnoreCase: Compare strings using ordinal sort rules and ignoring the case of the strings being compared.
To check Y or y ignoring case, you should use string.Equals(string,StringComparison) overload.
while (Console.ReadLine().Equals("Y", StringComparison.InvariantCultureIgnoreCase));
Please see the The Turkish İ Problem and Why You Should Care before using ToUpper or ToLower for string comparison with ignore case.
Your current code is reading the lines from console twice, that is why your code is holding up for the 2nd value.
As Austin just pointed out, you are using ReadLine twice in the while loop statement.
One thing worth mentioning is try to follow the rule of modularity, it will help speed up implementing and debugging our code.
It's been a while since I did any C# programming so sudo-coding this in Java style.
Since it's a command line programming you are probably have to validate user input more than once. One thing I would do is make a utility class to contains common user input tasks.
public class TerminalUtil {
private TerminalUtil() {}
public static boolean isYes(String msg){ return (msg.ToUpper() == "Y" || msg.ToUpper() == "YES"); }
public static boolean isNo(String msg){ return (msg.ToUpper() == "N" || msg.ToUpper() == "NO"); }
// You also might want basic conditionals to check if string is numeric or contains letters.
// I like using recursion for command line utilities so having a method that can re-print messages is handy
public static void display(String[] messages){
for(String msg : messages){
Console.WriteLine(msg);
}
}
public static boolean enterYesOrNo(String[] messages, String[] errorMessages){
display(messages)
String input = Console.ReadLine();
if( isYes(input) ){
return true;
} else if( isNo(input) ){
return false;
} else {
display(errorMessages); // Maybe something like, you didn't enter a yes or no value.
enterYesOrNo(messages, errorMessages); // Recursive loop to try again.
}
}
}
Here is what the code to order a pizza might look like
public class OrderPizza{
public static int selectToppings(){
String[] message = new String[4];
message[0] = ("\nSelect additional topping/s\n");
message[1] = ("1 - Extra meat: 200");
message[2] = ("2 - Extra cheese: 100");
message[3] = ("3 - Extra veggies: 80\n");
int option = TerminalUtils.entryNumeric(message, {"You entered an non-numeric character, try again"} );
if( option > 0 && option <= 3 ){
return option;
} else {
Console.WriteLine("Number must be between 1 - 3, try again.");
return selectToppings();
}
}
public static Pizza order(){
Pizza pizza = new Pizza();
while(true){
int toppingCode = selectTopping();
pizza.addTopping(toppingCode);
if(!TerminalUtil.enterYesOrNo({"\nAdd more toppings? Y/N"}, {"Please enter a 'Y'es or 'N'o"}) ){
break;
}
}
}
}
The main benefit of this is that the business logic of the while loop has been reduced and you can reuse the code in TerminalUtils. Also this is by no mean a elegant solution, I'm lazy and it's 3am IRL, but it's should be enough to the ball rolling.
One thing you should probably reconsider doing is using integer codes to represent toppings. Using an enum might make things easier to implement.
I also notice that you add three different types of pizza's, which I'm assuming three separate objects.
Since you are looping to add toppings to a pizza, make an abstract class of pizza. This way you could extend it generic pre-built pizzas such as pepperoni or cheese and use the abstract pizza class if you want the customer to customize their order.
I didn't found better way than:
while ( str!="N" )
{
str = Console.ReadLine();
str = str.ToUpper();
if (str == "Y");
break;
};
I'm working on a simple password storage console application in c#.
I'm having a bit of a problem on a section that asks if the user would like to mask all password entries from that point on.
This is the section of code:
bool tryagain = true;
while(tryagain == true)
{
Console.WriteLine("Would you like to mask all other password entiries?(Y,N)");
string input = Console.ReadLine();
if (input == "y" | input == "Y")
//Something wrong, always passes to Your awnser was invalid
{
maskpass = true;
tryagain = false;
}
if (input == "n" | input == "N")
{
maskpass = false;
tryagain = false;
}
else
{
Console.WriteLine("Your awnser was invalid, would you like to try again?");
string yesno = Console.ReadLine();
if (yesno == "y" | yesno == "Y")
{
tryagain = true;
}
if (yesno == "n" | yesno == "N")
{
Environment.Exit(0);
}
}
}
The problem is when I run the code it always runs to the else statement.
I'm certain the mistake is very simple and I'm just being ignorant but anyone have any idea on whats going on here?
Use || instead of single |. The || mean or conditional, but single | is binary or.
I assume that the logic of your code says:
if input=='y' OR input=="Y", do something.
Another suggession yet. If my assumption right, you can achiev that with simple String.Equals overload:
if(input.Equals("y", StringComparison.InvariantCultureIgnoreCase)
{
//do something/
}
You can either use || or you can use the method of the String class String.equals. Since it is a String you are reading as input better use the String.equals method