So I'm currently working on a school assignment which is to design a program that allows the user to enter some text, and then the program checks:
The first letter of the first word is a capital letter (it needs to be lowercase)
That there are only letters and numbers in the entire user input
That there are no spaces in the user input
So the program does work but the issue I'm having is with the print statements, I'll post my code below and explain:
public static void main(String[] args) {
try (Scanner stdln = new Scanner(System.in)) {
String userInput;
boolean legal = true;
boolean style = true;
char input; //Checks the userInput variable to be sure that boolean is false if there's no lowercase letter at char0 + if there are no letters
char loop;
System.out.println("The program checks the properness of a proposed Java variable name.");
System.out.println("\nPlease enter a variable name (q to quit): ");
userInput = stdln.nextLine();
input = userInput.charAt(0);
do
{
if (!(Character.isLetter(input)))
{
legal = false;
}
if (userInput.contains(" "))
{
legal = false;
}
if (!(Character.isLowerCase(input)))
{
style = false;
}
for (int i = 1; i < userInput.length() &&legal; i++)
{
loop = userInput.charAt(i);
if (!(Character.isLetterOrDigit(loop)))
{
style = false;
}
}
if (!(legal) && !(style))
{
System.out.println("Illegal.");
}
else if (legal && !(style))
{
System.out.println("Legal, but uses poor style.");
}
else
{
System.out.println("Good.");
}
System.out.println("\nPlease enter a variable name (q to quit): ");
userInput = stdln.nextLine();
input = userInput.charAt(0);
} while (!(userInput.equalsIgnoreCase("q")));
}
}
}
So the code works and the first input I test comes out as it should, however, once I get a response that isn't "Good.", then the same response will print for every entry, here's a sample from a session I just did:
The program checks the properness of a proposed Java variable name.
Please enter a variable name (q to quit):
streetAddress2
Good.
Please enter a variable name (q to quit):
StreetAddress2
Legal, but uses poor style.
Please enter a variable name (q to quit):
streetAddress2
Legal, but uses poor style.
Please enter a variable name (q to quit):
Street Address2
Illegal.
Please enter a variable name (q to quit):
streetAddress2
Illegal.
In that sample session, 3 and 5 should return the statement "Good." but for some reason, it just prints the statement from the previous entry. I'm still fairly new to Java so I'm a little stumped. Any ideas?
You have to reset legal and style to true at the start of each iteration. However, it is not the only problem with your code. The logic is not correct.
Right now in the for loop you check all the characters being letters or digits. If this condition fails you set style to false. However, you should set legal to false instead, because such identifiers are not allowed.
Also, when you print the result you don't check the conditions correctly. For example, if legal is false, but style is true your code will print Good.
You forgot to reset to true your legal and style boolean variables.
At every iteration, the legal and style variables will keep containing the result of the previous input. For example, if on your first input you immediately write a variable name with an illegal syntax and poor style, you'll see that any following name will show the same result. Even though those names are good or they only lack in style, the output will still be the same (wrong) because both variables have been left to false and nothing sets them back to true.
Besides, the logic to print the output messages didn't account for all combinations correctly.
Both variable logic and output printing could be re-written as follows:
do {
//forgotten reset
legal = true;
style = true;
//excat same implementation of yours
if (!(Character.isLetter(input))) {
legal = false;
}
if (userInput.contains(" ")) {
legal = false;
}
if (!(Character.isLowerCase(input))) {
style = false;
}
for (int i = 1; i < userInput.length() && legal; i++) {
loop = userInput.charAt(i);
if (!(Character.isLetterOrDigit(loop))) {
style = false;
}
}
//If it's illegal it does not matter whether the variable name has a poor or good style, it's illegal anyway
if (!legal) {
System.out.println("Illegal.");
//If we're in this else branch then the variable name is legal, but we have to check its style.
//If it has poor style then we print the "poor style" message.
} else if (!style) {
System.out.println("Legal, but uses poor style.");
} else {
//Last case where the variable name is legal and has a good style
System.out.println("Good.");
}
System.out.println("\nPlease enter a variable name (q to quit): ");
userInput = stdln.nextLine();
input = userInput.charAt(0);
} while (!(userInput.equalsIgnoreCase("q")));
Related
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.
In this method, it prompts the user to enter the value of their insured home. For some reason, it is getting stuck when the user inputs
static double promptHomeInsVal(){
double homeInsVal;
className promptHomeInsVal = new className();
do{
do{
System.out.printf("%nPlease enter the insured value of your home: ");
homeInsVal = promptHomeInsVal.input.nextDouble();
validateNumber(!promptHomeInsVal.input.hasNextDouble());
}while(promptHomeInsVal.repeat == true);
homeInsVal = promptHomeInsVal.input.nextDouble();
if(homeInsVal <= 0){
System.out.println("The insured value of your home cannot be less than or equal to 0. ");
promptHomeInsVal.repeat = true;
}
else{
promptHomeInsVal.repeat = false;
System.out.println("Home insurance value == " + homeInsVal);
}
}while(promptHomeInsVal.repeat == true);
return homeInsVal;
}
Here is validateNumber()
static void validateNumber(boolean repeat){
className validateNumber = new className();
if(repeat == true){
System.out.println("Warning: You entered an invalid integer or floating-point value. ");
}
}
When the prompt comes up "Please enter the insured value of your home: " it is suppose to take the input and move on. Right now, it is getting stuck
I feel that a significant part of the code is missing, and as far as I can see the problem should be in that part of the code. You should include into your question the code of the class className (which seems to be an error by itself).
In addition to that, I see some minor coding style mistakes in your code. You did not ask for such advice, but let me note that anyBooleanVariable == true is just the same as anyBooleanVariable.
Also validateNumber is the name of a method and the same time the name of a local variable inside the same named method. It is possible, but this is confusing and not a recommended practice.
I have a problem with my program is not with the code is how I am going to do it that's the confusing part that I am stuck with. just to let you know I am a basic java coder I do not understand complicated stuff so bear in mind that my code isn't the best.
----------------------------------------------------------- program explaintion-----------------------------------------------------------------
let's get into the point of explaining how it works before I show you my problem, ok when you execute the program it prompts you a sort of like a menu in a video game but it's a text-based, it shows you different options like enter player details, play the math game show score and then quit. enter player details it tells player 1 to enter he/she name and then tells another one to input he/she player name then prompts you back to the menu. play the math game is where a player 1 is asked to input he/she math equation after that player 2 has to solve it if he gets it right he gets 10 points if no the player gets no points at all. then repeats for another player to input he/she math equation then prompts you back to the menu. show scores it shows who got the most scores in the math game it calculates who's got the most if both of them got the same score then means a tie then prompts you back to the menu. and the last thing the quit option when you choose that option it stops the program. if the player chooses a wrong choice he gets an error message and puts you back to the menu
ok here is the first class called menu and other class which is connected with menu called game factions
menu:https://gist.github.com/LOLMEHA/86ff28b038d85030e346785e953644e0
gamefactions:https://gist.github.com/LOLMEHA/f05a51e07c8823a0e65cebbf81cc52ef
so this section of code that I have trouble fingering it out myself
import java.util.*;
public class Gamefunctions // this is a core when player choosess one of these options from the menu
{
String[] player =new String[2];
double scorea = 0; // verribles of all the objects
double scoreb = 0;
int i;
Scanner input = new Scanner(System.in);
double answer = 0;
double numA, numB;
char operator;
char operator2;
boolean quit = false;
double sum1;
double sum2;
public void enterDetails(){ // if player select enter details
for ( i=0;i<2;i++) {// tell's player to input he/she's name and stores them
int c=i;
System.out.println("Welcome to the maths quiz game please input player name "+c++);
player[i] = input.next();
}
}
public void mathGame(){ // if player select enter details
System.out.println("Please enter your equation please "+player[0]+" press enter for each number and mathematical symbol"); // tells the player 1 to input
System.out.println("");
System.out.println("such as for ex input a number or how many you like, then hit enter and input such as /*-+^ hit enter, then input any number one or how many you like ");
String s=input.next();
numA = Double.parseDouble(s); // numa and numb and operator is the aera of player to input he/she equation
operator = input.next().charAt(0);
numB = input.nextDouble();
if () {
if (operator == '+') {// this is if operator is one of these like +-*/^ and then it works out the sum
answer = numA + numB;
}
if (operator == '-') {
answer = numA - numB;
}
if (operator == '*') {
answer = numA * numB;
}
if (operator == '/') {
answer = numA / numB;
}
if (operator == '^') {
answer = Math.pow(numA, numB);
}
} else {
System.out.println("error input like for an example '10' enter '+' enter '10'");
}
System.out.println("");
System.out.println(player[1]+"\t solve the equation"); // tells other player to slove the equation
sum2 = input.nextDouble();
if (sum2 == answer){// checks if the answer from the player is good or not if its good he/she gets 10 points if he/she gets it wrong gets no points and shows the right answer so the player learns from his/she mistakes
scoreb = scoreb + 10.00;
System.out.println("correct you got 10 points to your score");
System.out.println("");
} else{
System.out.println("incorrect you got no points the correct answer was:"+"" + answer);
}
you know when the program ask to player to input his math eqtion and outputs this and continues with the program and waiting for the user to input
public void mathGame(){ // if player select enter details
System.out.println("Please enter your equation please "+player[0]+" press enter for each number and mathematical symbol"); // tells the player 1 to input
System.out.println("");
System.out.println("such as for ex input a number or how many you like, then hit enter and input such as /*-+^ hit enter, then input any number one or how many you like ");
String s=input.next();
numA = Double.parseDouble(s); // numa and numb and operator is the aera of player to input he/she equation
operator = input.next().charAt(0);
numB = input.nextDouble();
let's say that the player inputs like this 10+10 enter but it will not work since they are stored in numA which is an int, I want to make a error message saying that you can not input like this 10+10 you have to input like this 10 enter + enter 10 enter so it will be able to work
if the player inputs it correctly it will continue the program
so if you have any problems with my explaintion of my plroblem pls ask so I can edit it thank you for time :)
Here’s the bit of your code I’m going to be looking at:
String s = input.next();
numA = Double.parseDouble(s);
operator = input.next().charAt(0);
numB = input.nextDouble();
if (/* Some condition */) {
// Calculate answer
} else {
System.out.println("error input like for an example '10' enter '+' enter '10'");
}
First up, a couple nitpicks: Java is not C. You don’t need to declare all your variables at the beginning of your code blocks. numA, numB and operator are never used outside this bit of code, so it makes sense to declare them in here as well.
You’re also using input.next() with Double.parseDouble() once, then input.nextDouble() the next time. Stick to one or the other, it’ll make debugging easier if something doesn’t work properly.
And finally, what happens if someone enters 10 +1 0? The error is silently ignored because the 1 gets picked up as part of the operator string then discarded by charAt(0). A more resilient parsing method here would be to fetch the entire String first, then check for length == 1 before calling charAt(0).
double numA = input.nextDouble();
String operatorString = input.next();
char operator;
if (operatorString.length() == 1) {
operator = operatorString.charAt(0);
} else {
// Handle error
}
double numB = input.nextDouble();
if (/* Some condition */) {
// Calculate answer
} else {
System.out.println("error input like for an example '10' enter '+' enter '10'");
}
Onto your question then: how do we detect an invalid input? Take a look at the documentation for Scanner#nextDouble() (emphasis mine):
public double nextDouble()
Scans the next token of the input as a double. This method will throw InputMismatchException if the next token cannot be translated into a valid double value. If the translation is successful, the scanner advances past the input that matched.
So we know nextDouble() can detect the invalid input for us. It does this in the form of an exception, which we can listen for (or catch) using a try ... catch statement:
try {
double numA = input.nextDouble();
} catch (InputMismatchException e) {
System.err.printf("Invalid input! Expected number, found '%s'.\n", input.next());
}
We could extend this and wrap the entire section of code in a single try ... catch, but then the user would have to start again if they make one mistake. A more user-friendly solution would be this:
double numA;
while (1) {
try {
numA = input.nextDouble();
break;
} catch (InputMismatchException e) {
System.err.printf("Invalid input, try again! Expected number, found '%s'.\n", input.next());
}
}
Note the even if you don’t print it, the call to input.next() is necessary to prevent an infinite loop.
Now we just need to do something similar for operator:
char operator;
while (1) {
String operatorString;
try {
operatorString = input.next();
if (operatorString.length() != 1) {
throw new InputMismatchException();
}
operator = operatorString.charAt(0);
break;
} catch (InputMismatchException e) {
System.err.printf("Invalid input, try again! Expected character, found '%s'.\n", operatorString);
}
}
This seems very similar to the previous snippet for a number - let’s try to refactor some of the common code here into a method:
#FunctionalInterface
public interface ScannerGetter<T> {
T apply() throws InputMismatchException;
}
public <T> T getValueFromScanner(ScannerGetter<T> getter, String type) {
while(1) {
try {
return getter.apply();
} catch (InputMismatchException e) {
System.err.printf("Invalid input, try again! Expected %s.");
}
}
}
There’s a lot going on in these few lines. The first part declares a functional interface - this is a basically a custom type of lambda function. We’ll come back to that in a moment.
The method itself (getValueFromScanner()) is a generic method. It allows us to use the same method with different types in place of the generic parameter (T) without duplicating it.
This is how you’d use the above method to retrieve your three inputs:
double numA = this.<Double>getValueFromScanner(() -> input.nextDouble(), "number");
char operator = this.<Char>getValueFromScanner(() -> {
operatorString = input.next();
if (operatorString.length() != 1) {
throw new InputMismatchException();
}
return operatorString.charAt(0);
}, "operator");
double numB = this.<Double>getValueFromScanner(() -> input.nextDouble(), "number");
// Once your code gets here, all three variables will have valid values.
Ok, so my computer teacher has asked us to make a simple game that asks the user to guess a radomly generated number, but I want to take it one step further and make it so that it display error messages when the user tries certain things. The problem here is that I am new to booleans and well, I am having a bit of trouble using java.util.Scanner and booleans. So, if anyone could take a quick look at this I would appreciate it.
import java.util.Scanner;
import java.util.Random;
public class MoreGuessing{
//Instantiation
Scanner reader = new Scanner(System.in);
Random number = new Random();
//Variables
int randomnumber = number.nextInt(10) + 1;
int cntr = 1;
static String decimalguessed;
String error1 = "Error001: Decimal found, please enter a whole number between 1-10." + "\n" + "Program terminated......";//Decimal portion error.
String error2 = "Please enter a positive number." + "\n" + "Program terminated......"; //Negative number error.
String error3 = "Unknown character entered." + "\n" + "Program terminated......"; //Unknown character error.
//Verifier
public static boolean verifyLetters() {
if (decimalguessed.matches("[a-zA-Z]+")){
return true;
}else{
return false;
}
}
public static void main(String [] args){
//Input and display
System.out.print("Please enter a whole number between 1-10: ");
decimalguessed = reader.nextLine();
//Process and Errors
while (decimalguessed != randomnumber) {
if (verifyLetters() != false){
System.out.println(error3);
System.exit(1);}
if (decimalguessed % 1 != 0) {
System.out.println(error1);
System.exit(1);}
if (decimalguessed < 0) {
System.out.println(error2);
System.exit(1);}
if (randomnumber != decimalguessed){
System.out.println("You've lost, please make another attempt.");}
System.out.print("Please enter a whole number between 1-10: ");
decimalguessed = reader.nextDouble();
cntr++;
}
if (cntr == 1) {System.out.println("Congratulations! You've guessed the number on your first attempt!");;
}
else {System.out.println("Congratulations! You've guessed the number, it took you " + cntr + " tries");}
}
}
You need to parse your input. decimalguessed is a string, and so you can't do comparisons like decimalguessed % 1.
You can convert it to an integer like this:
int guess = 0;
try {
guess = Integer.parseInt(decimalguessed);
} catch (NumberFormatException e) {
System.out.println("Your guess was not an integer: " + e.getMessage());
System.exit(1);
}
This will handle both cases where decimalguessed contains letters, and where it contains decimal points/fractions. decimalguessed is still a string, but guess now contains the integer version of it, so you can compare it to randomnumber properly. (Your loop would have never exited before, because a string is never == an integer)
Some other notes:
You should never have:
if (condition) {
return true;
} else {
return false;
}
This can always be simply replaced with
return condition;
It feels like you're very new to this. Welcome to programming!
So first, in Java generally you're not going to have all of that instantiation and variables stuff outside of your main function, unless you're going to make everything static. I would move all of that into your main function, un-static the decimalguessed variable and setup your verifyLetters function to take an argument of String decimalguessed. It may also be wise to check if the value is a number, rather than seeing if it is not a letter. There a lot of non-number, non-letter characters.
Once you've figured out that the guess is a number, you need to tell java it is one (cast it) to a decimal, then do you further comparisons against that decimal.
Darth Android also makes some good points, especially about booleans. You should never have the only result of an if/else be to return a boolean, just return the boolean. Also avoid comparisons to true/false, just do the if on the function/variable alone, or negate it with an '!' to check for false.
Good luck!
I wrote a name checker that uses a for loop to check if each individual character in the string is a letter, and I wrote an if statement within the for loop stating that if the if statement conditions are met, print "Your name is valid!" and break. But if the conditions are not met, rerun the loop.
public static void nameValid() {
Scanner in = new Scanner(System.in);
System.out.println("Enter your name");
String name = in.nextLine();
int q = name.length();
for (int i = 0; i < name.length(); i++) {
if (Character.isLetter(name.charAt(i)) && q >= 2) {
System.out.println("Your name is valid!");
break;
} else {
System.out.println("Your name is invalid! Please enter a valid name!");
nameValid();
}
}
}
If I enter a valid string the first time around, everything is fine, and it moves on to the second method. If I enter an invalid String, it gives me the expected error message and reruns the loop. But then when I enter a valid string after that, it continuously runs the loop. The output I get is this:
Enter your name
123
Your name is invalid! Please enter a valid name!
Enter your name
fred
Your name is valid!
Your name is invalid! Please enter a valid name!
Enter your name
It's not re-running the loop... it's entering a recursive function call.
(Use a debugger next time please.)
In your else block, you're calling the nameValid function recursively within a loop. Thus, when you finally do enter a valid name and hit the break line, the loop that originally called the function continues.