Checking user input with scanner - java

I am trying to implement a simulator that has certain commands the user can input.
One of these commands is "s" which when entered should step through one instruction of the assembly file. However there is another instruction with the format "s num" where the user can define just how many instructions they want to step through.
I check for this
if(input.equals("s"))
{
//check for num next
if(user.hasNextInt())
{
input = user.next();
step(Integer.parseInt(input), assembler);
}
else
{
step(1, assembler);
}
}
However the problem is if the user only enters "s" the scanner will wait for the next input rather than just calling step. My idea is if there is an int after the s was input then proceed with the num step, other wise just call step.
Any help is greatly appreciated!

I would split the input into two parts and then treat it. For example,
String input = user.nextLine();
String array[] = input.split(" ");
if(array.length<2){
//check for `s`
}else{
//check for `s num`
}

you could try this:
if(input.equals("s"))
{
step(1, assembler);
}
else if(input.startsWith("s") && input.length() > 2)
{
step(Integer.parseInt(input.substring(input.indexOf(" ")+1)), assembler);
}
If control were to go inside the else if block, the current solution assumes that there is always a number after the String s with a white space delimiter in between them, but you can go on further and do more validations if necessary.

Related

Creating a menu for user to make a choice and determine if it is a Palindrome

Example output
file1.txt contents
I have to do a project to determine whether user input is a Palindrome (same letters forwards as backwards). I must create a menu and the user selects whether to input through the console or through a file. I had no issue with reading from the console. I am having trouble producing the correct output through reading Files however.
For a file to be a palindrome, the whole file must be able to be read forwards and backwards and be equal. Then the file contents must be printed and labeled as a Palindrome. I am able to determine if a string is a palindrome within the file, but not the whole file itself. I tried to use .hasNextLine() and compare the lines, but the output is not exactly what is desired.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.InputMismatchException;
import java.util.Scanner;
public class PalindromeMachine { //begin class
public static void main(String[] args) { //begin main
boolean choice1 = false;
boolean choice2 = false;
boolean choice3 = false;
while (choice3 == false) {
//create a menu
System.out.println("Welcome to the Palindrome Machine!");
for (int i = 0; i < 35; i++) {
System.out.print("-");
}
System.out.printf("\n1. Read one word from the keyboard");
System.out.printf("\n2. Read one or more words from a file");
System.out.printf("\n3. Exit");
System.out.printf("\nEnter your selection: ");
//gather user input
Scanner user = new Scanner(System.in);
try {
int num = user.nextInt();
if (num > 3 || num < 1) {
System.out.println("Invalid menu option");
}
if (num == 1) {
choice1 = true;
}
if (num == 2) {
choice2 = true;
}
if (num == 3) {
choice3 = true;
}
} catch (InputMismatchException e) {
System.out.println("Invalid menu option");
}
//based on user selection, read in the word or read in lines from a file
while (choice1 == true) {
System.out.printf("Enter the word you would like to check: ");
String checkThis = user.next();
int front = 0;
int back = checkThis.length() - 1;
while (front < back) {
if (checkThis.charAt(front) != checkThis.charAt(back)) {
choice1 = false;
System.out.printf("%s: this word is not a palindrome\n\n", checkThis);
}
front++;
back--;
}
if (choice1 == true) {
System.out.printf("%s: this word is a palindrome\n\n", checkThis);
choice1 = false;
}
} //end while for choice 1
//read from file and determine if palindrome
while (choice2 == true) {
System.out.printf("Enter the file you would like to check: ");
String name;
name = user.nextLine();
try {
File pali = new File(name);
Scanner userRead = new Scanner(pali);
while (userRead.hasNextLine()) {
String checkThis = userRead.nextLine();
//palindrome info
int front = 0;
int back = checkThis.length() - 1;
while (front < back) { //palindrome
if (checkThis.charAt(front) != checkThis.charAt(back)) {
choice2 = false;
System.out.printf("\n%s: this file is not a palindrome",
checkThis);
}
front++;
back--;
} //end palindrome
if (choice2 == true && userRead.hasNextLine() != false) {
System.out.printf(checkThis
+ ": this file is a palindrome\n");
choice2 = false;
} else {
System.out.println("");
System.out.printf(checkThis);
}
} //end of while the file has text
} catch (FileNotFoundException e) {
System.out.printf("\nInvalid file");
}
} // end choice 2
//loop until the user exits + catch inputmismatch
} // end while it loop until exit
} //end main
} //end class
If your intent is to read the entire file and then check if the entire contents are a palindrome or not, then lines in general are a bit of a complicated mess.
Is:
Hello, there!
!ereht ,olleH
A palindromic file? Note that it ends in a newline, so if you attempt to compare byte-for-byte, it's not. If the intent is that it is supposed to 'count', then presumably you'd first trim (lop any whitespace off of the front and back of the entire thing) and then compare byte-for-byte?
If the file's encoding involves characters smearing out over bytes (common - UTF_8, the most common encoding, can do that for any character that isn't simple ASCII), byte-for-byte fails immediately, so I guess character-by-character? Java's 'character' is actually part of surrogate pairs, so symbols from the higher unicode planes, such as emoji, will thus immediately cause trouble (as the emoji is two characters, and therefore won't be the same backwards and forwards). Just go with 'eh, whatever, no files will contain emoji'? Or try to compare codepoints instead?
What about commas, capitals, and other symbol characters? Is this:
Hello, there!
Ereht, olleh!
supposed to 'count'? If you look at Just the actually letters and forget about casing, it is. But a char-by-char comparison will obviously fail. Before you say: That's not palindromic, the usual "A man, a plan, a canal, Panama!" requires that you disregard non-letters and disregard casing.
In any case, it all starts with reading the entire file as a string; Scanner is designed to read tokens (tokens are the things in between the separator), and it has some ugly misplaced baggage in the form of the nextLine() method that you probably shouldn't be using. In any case, it can't read the entire file in one go which makes this vastly more complicated than it needs to be, so step 1 is do not use it.
There's the new file API which is great for this:
import java.nio.file.*;
Path p = Paths.get(fileName);
String contents = Files.readString(p);
That will read the entire contents. We can then remove everything that isn't a letter from it:
contents.toLowerCase().replaceAll("[^a-z]", "");
That thing is a 'regular expression' which is a mini language for text manipulation. [^...] is 'match any character that isn't mentioned here', and a-z is naturally, everything from a to z. In other words, that says: Take the input, lowercase everything, then replace all non-letters with blank, thus giving you only the letters. I turns "A man, a plan, a canal, Panama!" into "amanaplanacanalpanama".
It even gets rid of newlines entirely.
Now you can use the principle at work in your code (start from the beginning and end, fetch the characters there, compare them. If not equal - it is not a palindrome. If equal, increment your 'front pointer', decrement your 'back pointer', and keep going with the comparisons until your pointers are identical, then it is a palindrome.
Scanner has only two uses:
Keyboard input. In which case you should never use .nextLine() (nextLine is broken. It does what the javadoc says it does, which not what anyone expects, hence, do not use it for this) - and always call .useDelimiter("\\R") immediately after making the scanner. This configures it the way you'd expect. Use .nextX() calls to fetch info. next() for strings .nextInt() for integers, etc. All next calls will read entire lines.
Tokenizing inputs. This is only useful if the input is defined in terms of tokens separated by separators. Only a few formats follow that kinda rule. Even your usual 'CSV' files don't, not really - you need custom CSV parsers for that.
"Read an entire file to see if it is palindromic" fits neither use.

Getting input of one or more rows ending with char sequence not only seperated by space or new line - java

I need to read a user input that begins with "begin", "BEGIN" or "Begin" and the input can be one or more rows until user writes "end", "END" or "End". End is separated from previous String(s) with non-letter character (new line, space or "}" and so on).
I have tried something like this, but I know that's wrong.
String everything = sc.next();
while (true) {
String part = sc.next();
part.toUpperCase();
if (part.equals("END")) {
everything = everything.concat(part);
break;
} else {
everything = everything.concat(part);
}
}
I think your trying to do too many things at once. Your approach could work, but it's making things more complicated. First, get the user input and store it in a list. Once he presses END, then write some code that concatenates it, or whatever you want to do with it.
Scanner sc=new Scanner(System.in);
ArrayList<String> all=new ArrayList<>();
while (true) {
String part = sc.next();
if (part.toUpperCase().equals("END")) {
break;
}
all.add(part);
}
//then do whatever you want with that list.

How to check the same condition after each step without repeating the same code over and over in Java?

In my console application, I give the user the option to type "exit" at any point to return to the main menu. As the user enters data, i prompt him/her through the console for various things, and collect the data using scanner.
My question is how can I check to see if the user entered "exit" after each prompt (as opposed to the requested information) without having to use the same if statement after each step?
As I see it, any kind of while or for loops are insufficient because they only check the condition at the beginning, when I need to check the condition between inputs, and I need each input/prompt to execute only once per iteration.
The key here is that each prompt/code executed between the checks is DIFFERENT, so loops won't work.
Here is some example code:
String first;
String second;
Scanner input = new Scanner(System.in);
//prompt user for input
first = input.nextline();
if(first.equals("exit")){
//return to start menu
input.close();
return;
}
//prompt user for DIFFERENT input
second = input.nextline()
if(second.equals("exit")){
//return to start menu
input.close();
return;
}
If I understand you correctly, I recommend a do-while loop. It will first take text the first time, perform an action, and if it is exit it will break the loop, otherwise it will repeat.
do{
text = input.nextLine();
//whatever code you want here to perform with input
}while(!(text.equals("exit"));
Write a method...
public boolean isExit(String value) {
return value.equals("exit");
}
You can then check this method each time...
String value = input.nextLine();
if (!isExit(value) {
// Handle the normal text
} else {
// Handle the exit operations...
}
You could put additional code in the check, but I would prefer to have an additional method that handles the exit operation...for example...
String value = input.nextLine();
if (!isExit(value) {
// Handle the normal text
} else {
doExit();
}
Take a look at Defining Methods for more details...
Updated
Focus on the idea that a method should do a single job and have no side effects...
Having said that, I would setup my code in such away that if the user enters exit at the prompt, the method can exit of it's own accord, without the need for return; statement...
For example...
public int selectYourMeal() {
// Prompt...
int option = -1;
String value = input.nextLine();
if (!isExit(value) {
// Handle the normal text
} else {
option = EXIT_OPTION;
}
return option;
}
Where EXIT_OPTION is a special value, which the caller and identify and deal with as it sees fit.
I'm also old school, in that I was taught that a method should have one entry and one exit point, you really want to avoid having multiple exit points within your methods, as it becomes very difficult to follow the logic...
I would suggest you use an List<String> of words. You can return it. Also, it's a really bad idea to close a Scanner wrapping System.in, once you do you cannot re-open it.
List<String> words = new ArrayList<>();
Scanner input = new Scanner(System.in);
for (int i = 0; input.hasNextLine(); i++) {
String line = input.nextLine();
words.add(line);
if (line.equalsIgnoreCase("exit")) {
break;
}
}
System.out.println(words);
return words;

Scanner nextLine() issues

I've been working on a programming assignment that acts as a Scrabble dictionary for a while now. The program takes input from the user and outputs a file with a list of words, depending on what the user requests from a menu. The problem I've been having has to do with Scanner.nextLine().
I'm not aexactly sure why, but for some reason I have to press enter once sometimes before my code will take my input and store it as the variable. Essentially, I end up entering the input twice. I tried inserting Scanner.nextLine() around the code to "take up" the empty enter/spaces but it doesnt work, and I have to press enter multiple times to get it to process what I want.
Does anybody have any suggestions? I'd appreciate any and all help.
Here is a bit of the code:
System.out.println("Enter the length of the word you are" + " searching for.");
int n = -1;
while(!(n >=0)) {
if(in.hasNextInt())
n = in.nextInt();
else {
System.out.println("You have not entered a valid number.
Please enter a real number this time.");
in.nextLine();
}
}
in.nextLine();
System.out.println("Enter the first letter of the words" + " you are searching for.");
String firstLetter = "";
while(!(firstLetter.length() == 1)) {
if(in.nextLine().length() > 1) {
System.out.println("You have not entered a valid letter.
Please press enter and enter only one real letter.");
}
else if(in.hasNextInt()) {
System.out.println("Do not enter a number. Please enter one real letter.");
}
else {
in.nextLine();
firstLetter = in.nextLine();
break;
}
}
At the end of this, I have to press enter once and then input to get it to store anything in the variable firstLetter. I assume it has something to do with the nature of nextLine(), as the conditions using nextInt() give no issues.
It's because you're using both nextLine() and nextInt(), what's going on is that nextLine() is searching for a new line (enter) and nextInt will automatically stop the search if any integer is typed through System.in.
Rule of thumb: Just use Scanner.nextLine() for your input, then convert your string from Scanner.nextLine() accordingly through Integer.parseInt(string), etc.
I think you're overcompensating with too many nextLines. You may want to do that once to clear the line after the int is inputted, for example, to clear the newline, but the second time here just absorbs an extra line of input:
System.out.println("You have not entered a valid number. Please enter a real number this time.");
in.nextLine();//first time
}
}
in.nextLine();//this second time is unnecessary.
The same thing happens with your duplicate uses here:
in.nextLine();
firstLetter = in.nextLine();
break;
You should only add an extra in.nextLine() immediately between inputting nextSOMETHINGELSE() and another nextLine().
EDIT:
Additionally, note that whenever you call in.nextLine(), you are absorbing a line of input. For example, this line should be fixed:
if(in.nextLine().length() > 1){
because it reads in a line, using it up, and then checks whether that (now used-up) line is long enough.

Trouble with Scanner taking data from a command line using Java

I will admit, this is a school assignment... But I simply cannot figure out what I am doing wrong.
I have a hash table with an insert function. The following code is supposed to take a line of data from System.in in the format "Long String" (i.e. "32452 John"). The first token must be a Long for the ID number, and it must be followed by a String token for the name. When I run the program and I get to the portion where this must be executed (It is in a switch statement), I entered 'a' and hit enter. The command line immediately reads "Invalid value." (note: not VALUES, as that would mean it hit the nested if statement. It won't let me type in any data. Thank you in advance!
System.out.println("Enter ID and Name.");
//temp to take in the next line entered by the user
//inScan is the Scanner for System.in
temp = inScan.nextLine();
//Create Scanner for the line
Scanner tempScan = new Scanner(temp);
if(tempScan.hasNextLong()){
thisID = tempScan.nextLong();
if((tempScan.hasNext()) && (thisID>0)){
thisName = tempScan.next();
//The data will only be inserted if both segments of data are entered
myTable.insert(new Student(thisID, thisName));
}else{
System.out.println("Invalid values.");
}
}else{
System.out.println("Invalid value.");
}
Why do you need the second Scanner?
Example
String input = scanner.nextLine();
String[] tokens = input.split(" ");
Long id = Long.parseLong(tokens[0]);
String name = tokens[1];
And if you wanted to add your validation:
String input = scanner.nextLine();
if(input.contains(" ")) {
// You know there's a space in it.
String[] tokens = input.split(" ");
if(tokens.length == 2) {
// You know it's a value, followed by a space, followed by a value.
if(tokens[0].matches("[0-9]+")) {
// You know it only contains numbers.
Long id = Long.parseLong(tokens[0]);
}
}
}
I've not run it, but i guess your problem is that when you enter the text 'a' and hit enter, this line is false:
if(tempScan.hasNextLong()){
as you haven't entered a number. hence why it drops to the next block. If you enter something numerical first, i suspect your code with work. you probably need to add a 'while' loop around it, to run until it gets a number.
You already have a Scanner which reads from System.in, there's no need for another one. The second one you've made is a scanner for a String, which will never have a nextLong as it has nothing to scan after your String.
I won't write any code for you as this is homework, but stick to your original scanner when checking for user input instead.

Categories