Constraining user input to one of a specified set of values - c#

(I have tried finding a similar problem with no luck, so I am hoping maybe someone can provide a solution)
I have a do while loop in my first class with the goal of looping until the user inputs Feet, Meters or Yards as follows:
string convert = "";
do
{
Console.Clear();
Console.WriteLine("What conversion: Feet, Meters, Yards");
try
{
convert = Convert.ToString(Console.ReadLine());
}
catch (Exception)
{
Console.Clear();
Console.WriteLine("Incorrect conversion");
Console.ReadKey();
}
convert = Values.Input(convert);
Console.WriteLine(convert);
Console.ReadKey();
} while (_____); // Trying to loop while argument is thrown from my other class
Console.WriteLine("Continue on");
Console.ReadLine();
My separate values classes Input method:
public static string Input(string input)
{
string convert = input;
if (convert == "Meters")
{
input = "Meters";
}
else if (convert == "Feet")
{
input = "Feet";
}
else if (convert == "Yards")
{
input = "Yards";
}
else
{
throw new System.ArgumentException("Incorrect conversion");
//Trying to loop my main program if an ArgumentException is thrown here
}
return input;
}
What I've attempted:
} while (convert != "Meters" || convert != "Feet" || convert != "Yards");
Console.WriteLine("Continue on");
Console.ReadLine();
I've tried telling it to keep looping while convert is not Meters, Feet or Yards, but after the argument is thrown I am unable to continue the program.
Would I be able to continue my application after throwing this System.ArgumentException and if so what would I input into my while loop to allow this?

The problem is that the position where you call Values.Input() is outside the try/catch statement and when this throws an exception, it is not handled in the catch you've defined. So it will be caught up the callstack. Try placing the Values.Input(..) inside the try/catch statement.
string convert = "";
do
{
Console.Clear();
Console.WriteLine("What conversion: Feet, Meters, Yards");
try
{
convert = Convert.ToString(Console.ReadLine());
// ------- PASTE
convert = Values.Input(convert);
Console.WriteLine(convert);
// -----
}
catch (Exception)
{
Console.Clear();
Console.WriteLine("Incorrect conversion");
}
// XXXXXXXXX CUT
// XXXXXXXXX
Console.ReadKey();
} while (_____); //Trying to loop while argument is thrown from my other class
Console.WriteLine("Continue on");
Console.ReadLine();

This Input() function is pretty wild. What exactly is it doing? Basically nothing. You want to return some determinate value that indicates what type of unit it is, right?
Let's replace it with this:
public enum Unit { Meters, Feet, Yards }
public static Unit Input(string input)
{
switch (input.ToLowerInvariant())
case "meters": return Unit.Meters;
case "feet": return Unit.Feet;
case "yards": return Unit.Yards;
default: throw new System.ArgumentException("Incorrect conversion");
}
}
So after that we can fix the code:
Unit unit;
while (true)
{
Console.WriteLine("What conversion: Feet, Meters, Yards");
try
{
var input = Console.ReadLine();
unit = Values.Input(convert);
break; // if we get here we didn't throw an exception, so we can exit the loop
}
catch
{
Console.WriteLine("Incorrect conversion");
}
}
Console.WriteLine("Continue on");
Console.ReadLine();

Related

I am having trouble converting integer to string

namespace C2360_Ch07_Console1_InRange
{
class InRange
{
static void Main(string[] args)
{
Console.WriteLine("Num:");
String theLine;
theLine = Console.ReadLine();
try
{
theLine = Convert.ToInt32(Console.ReadLine());//cant convert
}
catch (FormatException)
{
Console.WriteLine("Input string was not in a correct format.");
}
IsWithinRange(theLine);
}
static void IsWithinRange(String theLine)
{
int Line1;
Int32.TryParse(Console.ReadLine(), out Line1);
try
{
if ((Line1 < 1) || (Line1 > 10))
{
throw new OverflowException();
}
}
catch (OverflowException)
{
Console.WriteLine("number must be between 1 and 10.");
}
Console.ReadLine();
}
}
}
What im trying to do is to convert string to integer to validate Main and IsWithinRange method. I get an error, where the comment is at, when I convert theLine to Int32.TryParse. Is this ever possible?
Anything would help?
I suggest extracting a method for reading integer value:
private static int ReadInteger(string title) {
while (true) {
Console.WriteLine(title);
if (int.TryParse(Console.ReadLine(), out int result))
return result;
Console.WriteLine("Incorrect syntax. Please, try again");
}
}
And then use it:
static void Main(string[] args) {
int theLine = 0;
while (true) {
theLine = ReadInteger("Num:");
// theLine is an integer, but we want an extra conditions meet:
if (theLine >= 1 && theLine <= 10)
break;
Console.WriteLine("The value must be in [1..10] range. Please, try again");
}
// from now on theLine is an integer in [1..10] range
//TODO: put relevant code here
}
Please, note, that exceptions FormatException, OverflowException are for exceptional behavior; here (user input validation), good old if is enough.
Edit: If you don't want to extract method (why?) but preserve IsWithinRange you can put something like this:
static void Main(string[] args) {
int theLine = 0;
while (true) {
Console.WriteLine("Num:");
if (!int.TryParse(Console.ReadLine(), out theLine)) {
Console.WriteLine("Syntax error. Please, try again");
continue;
}
if (IsWithinRange(theLine))
break;
Console.WriteLine("Sorry, the value is out of range. Please, try again");
}
// from now on theLine is an integer in [1..10] range
//TODO: put relevant code here
Where IsWithinRange can be
// Least Confusion Principle: For "Is [the value] Within Range" question
// the expected answer is either true or false
private static bool IsWithinRange(int value) {
return value >= 1 && value <= 10;
}

user should enter int, repeat if anything else is entered

First of all, I am a complete newbie at programming and c#..so here is my dilemma.
The user should only enter a number, entering anything else should fail and repeat the question.
I have been using try catch but, as soon as the error gets thrown the user doesn't have a second chance to enter a number again, I just get an error and the ConsoleApp Closes.
This is my code atm
static public int AskInt(string question)
{
try
{
Console.Write(question);
return int.Parse(Console.ReadLine());
}
catch (Exception)
{
throw new FormatException("Please Enter a Number");
}
}
Thank you in advance.
static public int AskInt(string question)
{
int answer = 0;
bool successfullyParsed = false;
do
{
Console.Write(question);
successfullyParsed = int.TryParse(Console.ReadLine(), out var parsedAnswer);
if(!successfullyParsed){
Console.WriteLine("Only Numbers, dude");
}
answer = parsedAnswer;
} while (!successfullyParsed);
return answer;
}
Explaining a bit. TryParse will return a boolean indicating the success of the operation and an out variable with the result.
I can't return the parsedAnswer because it is in the context of the do loop.
You can make this code less legible but short. I tried to make it this why to be kinda of self explanatory.
Use below code which uses TryParse of int to parse the entered string. If TryParse succeed then it will break the while loop.
public static int AskInt(string question)
{
int questionId;
while (true)
{
Console.Write(question);
string input = Console.ReadLine();
if (int.TryParse(input , out questionId))
{
break;
}
}
}
int i=1;
while(i==1)
{
try {
Console.WriteLine("your question");
int number= int.Parse(Console.ReadLine());
i=0;
}
catch (Exception)
{
i=1;
Console.WriteLine("Please Enter a Number");
}
}
static public int AskInt(string question)
{
for (;;)
{
Console.Write(question);
if (int.TryParse(Console.ReadLine(), out int result))
{
return result;
}
}
}

Try, Catch can't return correct value

This code aks for input from the user.
I wish to have the user try again after he sends wrong input and triggers any of the exceptions below.
After getInputNumber() is triggered after the exception and the user enters the right input as numbers, the return is then triggered which returns the correct number.
After this return, it returns to the FormatException thus deleting the correct number value and returning only 0.
How can I fix it to get the correct value, but also keep allowing the user to try again if he misses the correct input?
private static int getInputNumber()
{
int number = 0;
try
{
number = Convert.ToInt32(Console.ReadLine());
}
catch (Exception ex)
{
if (ex is FormatException)
{
Console.Clear();
Console.WriteLine("Wrong format! \nTry numbers instead.");
getInputNumber();
}
else if (ex is OverflowException)
{
Console.Clear();
Console.WriteLine("The number you entered is too large.\nTry a number between 1 and 2,147,483,647");
getInputNumber();
}
}
return number;
}
On your catch block try this:
...
if (ex is FormatException)
{
Console.Clear();
Console.WriteLine("Wrong format! \nTry numbers instead.");
return getInputNumber();
}
....
Instead of just calling it. This is because when you call the getInputNumber() method after first catch and it passes successfull, it gets back to your catch block(at this point number is still 0 since a exception occurs)
As stybl said, it's better to use a boolean check and while loop to keep asking for a valid input user.
First of all, I recommend using Int32.Parse instead. It won't make much of a difference in this particular case, but it is considered best practice. For your code to work you need to include return statements for every recursive call of getInputNumber:
private static int getInputNumber()
{
int number = 0;
try
{
number = int.Parse(Console.ReadLine());
}
catch (Exception ex)
{
if (ex is FormatException)
{
Console.Clear();
Console.WriteLine("Wrong format! \nTry numbers instead.");
return getInputNumber();
}
else if (ex is OverflowException)
{
Console.Clear();
Console.WriteLine("The number you entered is too large.\nTry a number between 1 and 2,147,483,647");
return getInputNumber();
}
}
return number;
}
However, making getInputNumber recurse like that is a bad idea. Instead, you should use an infinite loop. The final result will look something like this:
private static int getInputNumber()
{
int number = 0;
while (true)
{
try
{
number = int.Parse(Console.ReadLine());
break;
}
catch (Exception ex)
{
if (ex is FormatException)
{
Console.Clear();
Console.WriteLine("Wrong format! \nTry numbers instead.");
}
else if (ex is OverflowException)
{
Console.Clear();
Console.WriteLine("The number you entered is too large.\nTry a number between 1 and 2,147,483,647");
}
else
{
Console.Clear();
Console.WriteLine("Unexpected error!");
}
}
}
return number;
}

c# - Console App - Solving error when user presses enter without any numbers

The title is a bit messy in regards to getting what I want out there and it's my first time on here.
Basically I have converted my string into an int :
string _val = Console.ReadLine();
tempScoreToWin = Convert.ToInt32(_val);
And what I want to know is when user a presses enter without entering a value an error will occur and the application will end.
How can I get around this?
Here is my full code:
while (true)
{ //This will allow the player to manually change the score.
//------------------------------------------------------------------------------------------
string _val = "";
ConsoleKeyInfo key;
do
{
key = Console.ReadKey(true);
if (key.Key != ConsoleKey.Backspace)
{
double val = 0;
bool _x = double.TryParse(key.KeyChar.ToString(), out val);
if (_x)
{
_val += key.KeyChar;
Console.Write(key.KeyChar);
}
}
else
{
if (key.Key == ConsoleKey.Backspace && _val.Length > 0)
{
_val = _val.Substring(0, (_val.Length - 1));
Console.Write("\b \b");
}
}
}
while (key.Key != ConsoleKey.Enter);
Console.WriteLine();
//-----------------------------------------------------------------
tempScoreToWin = Convert.ToInt32(_val); // Converting the users input (Console.ReadLine()) into an integer.
if (tempScoreToWin > 0) // If the users input is higher than zero ...
{
scoreToWin = tempScoreToWin; // Reset the scoreToWin variable with the value of tempScoreToWin.
Console.WriteLine("The score has been set to {0}.", scoreToWin); // Let the user know that the score has been changed successfully.
break; // Break out of the while loop.
}
else
{ // If the player has not put a correct integer in ...
Console.WriteLine("The score has been set at a default of {0}.", scoreToWin); // then the score will be set to the default value of scoreToWin
break; // Break out of the while loop.
}
}
Console.ReadLine();
Console.Clear();
//-----------------------------------------------------------------
Cheers!
Using TryParse will allow you to parse a string for an integer while also checking if it succeeded.
if(int.TryParse(_val, out tempScoreToWin)
{
//Parse succeeded
}
else
{
//Parse failed
}
Brilliant! That worked MrZander. Thank you guys so much for the quick answer. I really appreciate it :)
if (int.TryParse(_val, out tempScoreToWin))
{
if (tempScoreToWin > 0) // If the users input is higher than zero ...
{
scoreToWin = tempScoreToWin; // Reset the scoreToWin variable with the value of tempScoreToWin.
Console.WriteLine("The score has been set to {0}.", scoreToWin); // Let the user know that the score has been changed successfully.
break; // Break out of the while loop.
}
else
{ // If the player has not put a correct integer in ...
Console.WriteLine("The score has been set at a default of {0}.", scoreToWin); // then the score will be set to the default value of scoreToWin
break; // Break out of the while loop.
}
}
else
{
//Parse failed
}

How do I only allow number input into my C# Console Application?

Console.WriteLine("Enter the cost of the item");
string input = Console.ReadLine();
double price = Convert.ToDouble(input);
Hello, I want the keyboard buttons, A-Z, brackets, question mark, etc to be disabled. I want it so if you type it in, it will not show up in the Console. I only want the numbers 1-9 to show up. This is in C# Console application. Thanks for the help!
try this code snippet
string _val = "";
Console.Write("Enter your value: ");
ConsoleKeyInfo key;
do
{
key = Console.ReadKey(true);
if (key.Key != ConsoleKey.Backspace)
{
double val = 0;
bool _x = double.TryParse(key.KeyChar.ToString(), out val);
if (_x)
{
_val += key.KeyChar;
Console.Write(key.KeyChar);
}
}
else
{
if (key.Key == ConsoleKey.Backspace && _val.Length > 0)
{
_val = _val.Substring(0, (_val.Length - 1));
Console.Write("\b \b");
}
}
}
// Stops Receving Keys Once Enter is Pressed
while (key.Key != ConsoleKey.Enter);
Console.WriteLine();
Console.WriteLine("The Value You entered is : " + _val);
Console.ReadKey();
This MSDN article explains how to read characters one at a time in a console window. Test each character as it is input with the Char.IsNumber() method, and reject those characters that fail the test.
In a while, I got a solution really short:
double number;
Console.Write("Enter the cost of the item: ");
while (!double.TryParse(Console.ReadLine(), out number))
{
Console.Write("This is not valid input. Please enter an integer value: ");
}
Console.Write("The item cost is: {0}", number);
See you!
Here is one approach. It's probably overkill if you're just starting out in C#, since it uses some more advanced aspects of the language. In any case, I hope you find it interesting.
It has some nice features:
The ReadKeys method takes an arbitrary function for testing whether the string so far is valid. This makes it easy to reuse whenever you want filtered input from the keyboard (e.g. letters or numbers but no punctuation).
It should handle anything you throw at it that can be interpreted as a double, e.g. "-123.4E77".
However, unlike John Woo's answer it doesn't handle backspaces.
Here is the code:
using System;
public static class ConsoleExtensions
{
public static void Main()
{
string entry = ConsoleExtensions.ReadKeys(
s => { StringToDouble(s) /* might throw */; return true; });
double result = StringToDouble(entry);
Console.WriteLine();
Console.WriteLine("Result was {0}", result);
}
public static double StringToDouble(string s)
{
try
{
return double.Parse(s);
}
catch (FormatException)
{
// handle trailing E and +/- signs
return double.Parse(s + '0');
}
// anything else will be thrown as an exception
}
public static string ReadKeys(Predicate<string> check)
{
string valid = string.Empty;
while (true)
{
ConsoleKeyInfo key = Console.ReadKey(true);
if (key.Key == ConsoleKey.Enter)
{
return valid;
}
bool isValid = false;
char keyChar = key.KeyChar;
string candidate = valid + keyChar;
try
{
isValid = check(candidate);
}
catch (Exception)
{
// if this raises any sort of exception then the key wasn't valid
// one of the rare cases when catching Exception is reasonable
// (since we really don't care what type it was)
}
if (isValid)
{
Console.Write(keyChar);
valid = candidate;
}
}
}
}
You also could implement an IsStringOrDouble function that returns false instead of throwing an exception, but I leave that as an exercise.
Another way this could be extended would be for ReadKeys to take two Predicate<string> parameters: one to determine whether the substring represented the start of a valid entry and one the second to say whether it was complete. In that way we could allow keypresses to contribute, but disallow the Enter key until entry was complete. This would be useful for things like password entry where you want to ensure a certain strength, or for "yes"/"no" entry.
This code will allow you to:
Write only one dot (because numbers can have only one decimal separator);
One minus at the begining;
One zero at the begining.
It means that you not be able to write something like: "00000.5" or "0000...-5".
class Program
{
static string backValue = "";
static double value;
static ConsoleKeyInfo inputKey;
static void Main(string[] args)
{
Console.Title = "";
Console.Write("Enter your value: ");
do
{
inputKey = Console.ReadKey(true);
if (char.IsDigit(inputKey.KeyChar))
{
if (inputKey.KeyChar == '0')
{
if (!backValue.StartsWith("0") || backValue.Contains('.'))
Write();
}
else
Write();
}
if (inputKey.KeyChar == '-' && backValue.Length == 0 ||
inputKey.KeyChar == '.' && !backValue.Contains(inputKey.KeyChar) &&
backValue.Length > 0)
Write();
if (inputKey.Key == ConsoleKey.Backspace && backValue.Length > 0)
{
backValue = backValue.Substring(0, backValue.Length - 1);
Console.Write("\b \b");
}
} while (inputKey.Key != ConsoleKey.Enter); //Loop until Enter key not pressed
if (double.TryParse(backValue, out value))
Console.Write("\n{0}^2 = {1}", value, Math.Pow(value, 2));
Console.ReadKey();
}
static void Write()
{
backValue += inputKey.KeyChar;
Console.Write(inputKey.KeyChar);
}
}
You can do it with a single line code as follows:
int n;
Console.WriteLine("Enter a number: ");
while (!int.TryParse(Console.ReadLine(), out n)) Console.WriteLine("Integers only allowed."); // This line will do the trick
Console.WriteLine($"The number is {n}");
You can change int into double in case you wanted to allow double instead of integers and so on.
string input;
double price;
bool result = false;
while ( result == false )
{
Console.Write ("\n Enter the cost of the item : ");
input = Console.ReadLine ();
result = double.TryParse (input, out price);
if ( result == false )
{
Console.Write ("\n Please Enter Numbers Only.");
}
else
{
Console.Write ("\n cost of the item : {0} \n ", price);
break;
}
}

Categories