replaceAll and loops? - java

My Computer Science class assignment requires that I write a program which determines if a word or phrase is a palindrome (is the same forward and backwards, ie "noon"). As part of this, I have to write a method which removes all punctuation and spaces, so they are not counted in determining if it is a palindrome. It also runs on a loop, allowing the user to input as many phrases they want until they indicate they're done. My problem is that when the word/phrase entered contains a space, somehow it terminates the loop and doesn't allow more input. The program works just fine, as long as the input has no spaces. Here's my code:
In class RecursivePalindrome:
public String removePunctuation(String s){
s = s.replaceAll("\\.","");
s = s.replaceAll("!","");
s = s.replaceAll(",","");
s = s.replaceAll(" ","");
s = s.replaceAll("'","");
s = s.replaceAll("-","");
s = s.replaceAll("\\?","");
return s;
}
public boolean isPalindrome(String s) {
s = removePunctuation(s);
String firstChar = s.substring(0,1);
String lastChar = s.substring(s.length()-1);
if (s.length() == 1){
return true;
}
if (s.length() == 2 && firstChar.equalsIgnoreCase(lastChar)){
return true;
}
if (!firstChar.equalsIgnoreCase(lastChar)){
return false;
}
return isPalindrome(s.substring(1, s.length() - 1));
}
In class RecursivePalindromeTester:
public static void main(String[]args){
//Create objects
Scanner in = new Scanner(System.in);
RecursivePalindrome palindrome = new RecursivePalindrome();
//Output
for (String again = "Y"; again.equalsIgnoreCase("Y"); again = in.next())
{
//Prompt for input
System.out.println();
System.out.print("Enter a word or phrase: ");
String phrase = in.next();
//Output
if (palindrome.isPalindrome(phrase)){
System.out.println("This is a palindrome.");
}
else
System.out.println("This is not a palindrome.");
System.out.print("Another word or phrase? (Y/N): ");
}
}
The output should be:
"Enter word or phrase: <input>mom- mom!
This is a palindrome
Another word or phrase? (Y/N): <input>Y
Enter a word or phrase: <input>Dog?
This is not a palindrome
Another word or phrase? (Y/N): <input>N"
Terminate
But instead I get:
"Enter word or phrase: <input>mom- mom!
This is a palindrome
Another word or phrase? (Y/N):"
Terminate
I really have no idea why a space would cause the loop to terminate, especially since it doesn't do this with any other punctuation.

Totally agreed with #Ilya Bursov comment,
You should use in.nextLine() instead of in.next() , there are big difference between both methods
next() can read the input only till the space. It can't read two words separated by a space. Also, next() places the cursor in the same line after reading the input.
nextLine() reads input including space between the words (that is, it reads till the end of line \n). Once the input is read, nextLine() positions the cursor in the next line
Try like this ,
class RecursivePalindromeTester {
public static void main(String[] args) {
//Create objects
Scanner in = new Scanner(System.in);
RecursivePalindrome palindrome = new RecursivePalindrome();
//Output
for (String again = "Y"; again.equalsIgnoreCase("Y"); again = in.nextLine()) {
//Prompt for input
System.out.println();
System.out.print("Enter a word or phrase: ");
String phrase = in.nextLine();
//Output
if (palindrome.isPalindrome(phrase)) {
System.out.println("This is a palindrome.");
}
else
System.out.println("This is not a palindrome.");
System.out.print("Another word or phrase? (Y/N): ");
}
}
}

Related

How to re-write an input loop to not contain code repetition?

I have the following code, which continues to ask the user to enter a letter as long as the letter is either "a" or "b":
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
String letter;
System.out.print("Enter a letter: ");
letter = scan.nextLine();
while(letter.equals("a") || letter.equals("b"))
{
System.out.println("You entered: " + letter);
System.out.print("Enter a letter: ");
letter = scan.nextLine();
}
}
}
But the following code is repeated twice:
System.out.print("Enter a letter: ");
letter = scan.nextLine();
Is there a way to make the above code only appear one time?
while (true) {
System.out.print("Enter a letter: ");
String letter = scan.nextLine();
if (!letter.equals("a") && !letter.equals("b"))
break;
System.out.println("You entered: " + letter);
}
This is the classic example of a loop that is neither naturally while-do nor do-while — it needs to exit from the middle, if you want the same behavior and also to reduce code duplication.
(Notice also that the variable declaration letter has been moved to an inner scope since it is no longer needed in the outer scope.  This is a small positive indication.)
As an alternative to while (true) some languages allow degenerate for-loop as in for(;;).
The below reverses the logic of the conditional loop exit test, at the expense of more control flow logic.
while (true) {
System.out.print("Enter a letter: ");
String letter = scan.nextLine();
if (letter.equals("a") || letter.equals("b")) {
System.out.println("You entered: " + letter);
continue;
}
break;
}
(There is no difference between these in efficiency terms — these are equivalent at the level of machine code.)
do while loop
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
String letter;
do{
System.out.print("Enter a letter: ");
letter = scan.nextLine();
System.out.println("You entered: " + letter);
}while(letter.equals("a") || letter.equals("b"));
}
}
It will loop once first, and then continue again if the statment is true.
You need to perform three sequential actions in a loop:
read the input entered by the user;
validate the input;
print the input, but only if it is valid.
That means that conditional logic must reside inside the loop before the statement that prints the input. And that makes the condition of the loop redundant. Instead, we can create an infinite loop with a break statement wrapped by a condition, that validates the input.
While loop
That's how it can be done using a while loop:
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String letter;
while (true) {
System.out.print("Enter a letter: ");
letter = scan.nextLine();
if (!letter.matches("[ab]")) break;
System.out.println("You entered: " + letter);
}
}
Method matches() that expects a regular expression as argument is used in the code above to simplify the termination condition.
For more information on regular expressions, take a look at this tutorial
For loop
Regarding the advice of utilizing a for loop - that's doable, but by its nature the task of reading the user input fits better in the concept of while loop because we don't know the amount of data in advance, and the iteration can terminate at any point in time.
Also note syntax of the for statement consists of three parts separated with a semicolon:
initialization expression - allow to define and initialize variables that would be used in the loop;
termination expression - condition which terminates the execution of the loop;
increment expression - defines how variables would change at each iteration step.
All these parts are optional, but the two semicolons ; inside the parentheses always have to be present.
Because as I've said earlier, the input needs to be validated inside the loop, we can't take advantage from the termination expression and increment expression.
For the sake of completeness, below I've provided the version of how it can be achieved using a for loop:
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
for (String letter = "a"; ;) {
System.out.print("Enter a letter: ");
letter = scan.nextLine();
if (!letter.matches("[ab]")) break;
System.out.println("You entered: " + letter);
}
}
The only advantage is that the scope of the variable letter was reduced. But approach of utilizing while loop is more readable and expressive.
Alternative approach
Another option is to preserve your initial structure of the code:
initialize the variable letter before the loop, at the same line where it is defined;
enter the loop if letter holds a valid input;
print the input and reassign the variable.
But in order to avoid duplication of the code line responsible for printing the prompt and reading the input will be extracted into a separate method.
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String letter = readInput(scan);
while (letter.matches("[ab]")) {
System.out.println("You entered: " + letter);
letter = readInput(scan);
}
}
public static String readInput(Scanner scan) {
System.out.print("Enter a letter: ");
return scan.nextLine();
}
As Bobulous mentioned, a do-while loop is another simple solution. If duplicating the conditional is still a deal-breaker for you, though, you can also create a function that returns a boolean, and, when true, prints the extra text.
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
String letter;
do
{
System.out.print("Enter a letter: ");
letter = scan.nextLine();
} while(inputIsAOrB(letter));
}
public static boolean inputIsAOrB(String input) {
if (input.equals("a") || input.equals("b"))
{
System.out.println("You entered: " + input);
return true;
}
else
{
return false;
}
}
A while loop with a break after executing your second print command will limit the code to only asking for a single input.
Scanner ct = new Scanner(System.in);
String input;
System.out.print("Please enter either 'a' or 'b': ");
input = ct.nextLine();
while(input.equals("a") || input.equals("b")){
System.out.println("You entered: " + input);
break;
}
You can also view the problem as generating and processing a stream of strings. The side effects in the generator may trigger some philosophical discussions, otherwise I think it is quite clean:
Stream.generate(() -> {
System.out.print("Enter a letter: ");
return scan.nextLine();
})
.takeWhile(str -> str.equals("a") || str.equals("b"))
.forEach(str -> System.out.println("You entered: " + str));
... which will run like this:
Enter a letter: a
You entered: a
Enter a letter: b
You entered: b
Enter a letter: c
Process finished with exit code 0
Simply
List<Character> expectedChars = new ArrayList<>();
expectedChars.add('a');
expectedChars.add('b');
while(!expectedChars.contains(line = scan.nextLine())) {
System.out.println("Not expected");
}
// Now has a expected char. Proceed.
I without using any break or if-else externally (I am using ternary operator though) within control loop, you can also use below :
Scanner scanner = new Scanner(System.in);
boolean flag=true;
while (flag) {
System.out.println("enter letter");
String bv = scanner.nextLine();
flag=bv.matches("a|b");
System.out.println(flag?"you entered"+bv:' ');
}
with for loop, it can be even simpler :
Scanner scanner = new Scanner(System.in);
for (boolean flag = true; flag;) {
System.out.println("enter letter");
String bv = scanner.nextLine();
flag = bv.matches("a|b");
System.out.println(flag ? "you entered" + bv : ' ');
}
Or if you ok for having whitspace for first run:
Scanner scanner = new Scanner(System.in);
String aa=" ";
String bv=null;
for (boolean flag = true; flag;aa=(flag?"you entered: "+bv:" ")) {
System.out.println(aa);
System.out.println("enter letter");
bv = scanner.nextLine();
flag = bv.matches("a|b");
}
You can easily run a while loop until letter = "a" or letter = "b". Code will start the while loop with intial "" value of the letter and get the new value by scanner. Then it check the new value of the letter before starting the next round of the loop.
package com.company;
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
String letter = "";
while(!(letter.equals("a") || letter.equals("b")))
{
System.out.print("Enter a letter: ");
letter = scan.nextLine();
System.out.println("You entered: " + letter);
}
}
}
Similar as previous answer, but from a code readability perspective i would create an array of valid characters instead and use in condition. That results in the more "text like" condition below reading "if not validCharacters contains letter":
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
List<String> validCharacters = List.of("a", "b");
while (true) {
System.out.print("Enter a letter: ");
String letter = scan.nextLine();
if (!validCharacters.contains(letter)) {
break;
}
System.out.println("You entered: " + letter);
}
}
Your code just needed a little tweak to make it work, although you can use many more efficient approaches but here it is:
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
String letter = "a";
while(letter.equals("a") || letter.equals("b"))
{
System.out.print("Enter a letter: ");
letter = scan.nextLine();
System.out.println("You entered: " + letter);
}
}
}

How do I print a letter based on the index of the string?

I want to print a letter instead of the index position using the indexOf(); method.
The requirement is that: Inputs a second string from the user. Outputs the character after the first instance of the string in the phrase. If the string is not in the phrase, outputs a statement to that effect. For example, the input is 3, upside down, d. The output should be "e", I got part of it working where it inputs an integer rather than a string of that particular position. How would I output a string?
else if (option == 3){
int first = 0;
String letter = keyboard.next();
first = phrase.indexOf(letter,1);
if (first == -1){
System.out.print("'"+letter+"' is not in '"+phrase+"'");
}
else {
System.out.print(first + 1);
}
}
String.charAt(index)
You can access a single character, or a letter, by caling método charAt() from String class
Example
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
String phrase = keyboard.nextLine();
char firstLetter = phrase.charAt(0);
System.out.println("First Letter : " + firstLetter);
}
So, running this code, assuming the input is StackOverFlow, the output will be S
In your code I think doing the follow will work:
Your Code
String letter = keyboard.next();
first = letter.charAt(0);
That might help!
Based on those comments
So, what you want is print the first letter based on a letter the user
has input? For example, for the word Keyboard, and user inputs letter
'a' the first letter might be 'R'. Is that it? – Guerino Rodella
Yes, I have to combine both the indexOf(): method and the charAt():
method – Hussain123
The idea is get next letter based on user input letter.
I'm not sure I wunderstood it, but this is my shot
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
String phrase = "keyboard";
String userInput = keyboard.nextLine();
boolean notContainsInputValue = !phrase.contains(userInput);
if (notContainsInputValue) {
System.out.println("The input value doesn't exists");
return;
}
char firstLetter = userInput.charAt(0);
int desiredIndex = 0;
for (int i = 0; i < phrase.length(); i++) {
if (phrase.charAt(i) == firstLetter) {
desiredIndex = i;
break;
}
}
System.out.println("The index for your input letter is: " + desiredIndex);
System.out.println("Next letter based on input value is: " + phrase.charAt(desiredIndex + 1));
}
The Output
The index for your input letter is: 5
Next letter based on input value is: r
Hope that helps you.

Reversing the words in a sentence using Stack

Does my reverse method only work if I input a series of words all at once?
My task was to: Write a complete method that reads a series of Strings from the user. The user enters "end" to stop inputting words. Then, output the Strings in reverse order of how they were entered. Do not output the String “end”.
Use a stack to accomplish this task. Invoke only the methods push, pop, peek, and isEmpty on the stack object.
Here is how it is supposed to run:
Enter a word or 'end' to quit: Hello
Enter a word or 'end' to quit: Java
Enter a word or 'end' to quit: World
Enter a word or 'end' to quit: end
You entered (in reverse):
World
Java
Hello
But mine runs:
Enter a word or 'end' to quit: Hello
Enter a word or 'end' to quit: Java
Enter a word or 'end' to quit: World
Enter a word or 'end' to quit: end
You entered (in reverse): end
Here is what I have so far:
import java.util.Scanner;
import java.util.Stack;
import java.util.regex.Pattern;
public class Stack1 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = "end";
do {
System.out.printf("Enter a word or 'end' to quit: ");
input = scanner.nextLine();
if (input == null || input.length() == 0) {
System.out.println("Invalid! Try again...");
return;
}
} while(!input.equalsIgnoreCase("end"));
String reverse = reverse(input);
System.out.printf("You entered (in reverse): %s", reverse);
}
private static String reverse(String inputString) {
String[] str = inputString.trim().split(Pattern.quote(" "));
Stack stack = new Stack();
for(String input : str) {
stack.push(input);
}
StringBuilder builder = new StringBuilder();
while( !stack.isEmpty()) {
builder.append(stack.pop()).append(" ");
}
return builder.toString();
}
}
read input.
push it in stack.
if input equals "end" then stop reading input.
pop stack until stack gets empty.
Code
import java.util.Scanner;
import java.util.Stack;
public class Stack1 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String input = "";
Stack stack = new Stack();
while(true){
System.out.printf("Enter a word or 'end' to quit: ");
input = in.next(); // to read a word use next() method.
if(input.equalsIgnoreCase("end")){ break; }
if(!input.equals("")) stack.push(input);
}
System.out.println("You entered (in reverse): ");
while(!stack.isEmpty())
System.out.println(stack.pop());
}
}
Your loop is overwriting input on each iteration. To make it work with your reverse() method, you'll want to concat each word incrementally with a space:
String input = "";
while (true) {
System.out.printf("Enter a word or 'end' to quit: ");
String next = scanner.nextLine();
if (next == null || next.length() == 0) {
System.out.println("Invalid! Try again...");
return;
}
if (next.equalsIgnoreCase("end")) {
break;
}
input += next + " ";
}
Alternatively, you can populate the stack directly in the loop and skip the string splitting:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Stack<String> stack = new Stack<>();
while (true) {
System.out.printf("Enter a word or 'end' to quit: ");
String next = scanner.nextLine();
if (next == null || next.length() == 0) {
System.out.println("Invalid! Try again...");
return;
}
if (next.equalsIgnoreCase("end")) {
break;
}
stack.push(next);
}
System.out.println("You entered (in reverse):");
while (!stack.isEmpty()) {
System.out.println(stack.pop());
}
}
Note that the latter solution correctly reverses multi-word inputs, whereas the concatenation approach can't differentiate between lines and words.
This is because your input variable contains only "end". Thus whenever you call reverse function ,it only reverses end String.
String reverse = reverse(input);//input="end"
the problem comes from this place
#Toby Speight thanks for your advice.
by the way I am a English newcomer,I'm pleased to accept any suggestion.
What I'm trying to say is to learn debug your program when you meet problems.In this case: you want the program print a reversed String to the console .but you got a strange answer.now you need to consider where the answer maybe comes from ?
and then just print it before you use it like below
String reverse = reverse(input);//we said you think the problem comes from this place.
System.out.printf("%s%n",input);//this is a key statement to debug--just print it
Now you and then consider where input is not what you want? and then just consider where input comes from?keep on doing this ,and then you can find where
your problem comes from.
On the other hand ,there have a lot of method to debug,you can use IDE debug your program and it will be more efficient ,what's more you can use a log file and so on.
You're using a do-while loop, which is why "end" gets added to the array.
To reverse the string, you can either use a for loop and reverse it yourself:
StringBuilder reverseStr = new StringBuilder();
for (int i = str.size - 1; i >= 0; i--) {
reverseStr.append(str[i]);
}
Or use something like Apache Commons Lang StringUtils.reverse().

How can I compare an input value with each value of an array?

Problem
I want to be able to ask the user to enter a word, then loop through an array that contains words, and search whether that word is in the array.
If the word is not in the array, then it will continue to ask the user for a word until that word is found in the array.
If the word is found in the array, then it will print it out and do something with that word. Loop ends.
Note:
I do not want to use a flag variable. Instead, I want to use only a loop to go through each value in the array and compare it with each new word entered by the user then stop upon the word matching in the array. This method should not use any flag values that stops when changing from false to true, and vice verca.
Program.Java
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String userInput;
String array[] = {"Hello", "World"};
System.out.print("Enter word: ");
userInput = input.next();
for(String i : array)
while(!choice.equals(i)) {
System.out.print("Input not found in array. Enter new value: ");
userInput = input.next();
}
System.out.println("Word found in array.");
}
Unintended Output
Instead of stopping when the value in the array is found, it continues to ask for another input, and never terminates.
Example
Enter word: month
Input not found in array. Enter new value: Hello
Input not found in array. Enter new value: World
[...]
Input not found in array. Enter new value:
Intended Output:
Enter word: month
Input not found in array. Enter new value: Hello
Word found in array.
How I want to implement it
To loop through all the values in the array. Compare user input with each value in the array. If the user input matches none of the values in the array, then continue to ask for a new word, until that word matches the value in the array.
Separate the process of finding the value from the process of asking for a value. This is two distinct operations:
Ask for a string
Given a string, search for it in your array (a proper array, declared as String[])
Here's a hint. I'd recommend breaking those things out.
public boolean findWord(String candidateWord) {
for(String word : string) {
if(word.equals(candidateWord)) {
return true;
}
}
return false;
}
public void askForWords() {
System.out.println("Find a word! ");
Scanner scan = new Scanner(System.in);
String candidateWord;
boolean found = false;
do {
System.out.print("What word do you want to find? ");
found = findWord(scan.nextLine());
if(!found) {
System.out.println("Can't find that - try again?");
System.out.print("What word do you want to find? ");
scan.nextLine();
}
} while(!found);
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String userInput;
String array[] = {"Hello", "World"};
System.out.print("Enter word: ");
userInput = input.next();
while (true) {
for(String i : array) {
if(userInput.equals(i)) {
System.out.println("Word found in array.");
return;
}
}
System.out.print("Input not found in array. Enter new value: ");
userInput = input.next();
}
}
Note the placement of while and for and the return statement
This code below should work perfectly fine for you. Your for loop actually checks a string both the times even if it is matched at the first attempt. Therefore, it is solved below by adding a boolean check and break at some attempts where the input string is matched. There were some syntax problems in your code which I solved as below:
import java.util.*;
import java.io.*;
public class abcd {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String userInput = "";
String[] array = {"Hello", "World"};
boolean check = true;
System.out.print("Enter word: ");
userInput = input.next();
while(true) {
for(String i : array) {
if(userInput.equals(i)) {
System.out.println("Word found in array.");
check = false;
break;
}
}
if(check) {
System.out.print("Input not found in array. Enter new value: ");
userInput = input.next();
continue;
}
break;
}
}
}

Prevent the user entering numbers in java Scanner?

I am having some trouble preventing the user from entering numbers with the scanner class. This is what I have:
package palindrome;
import java.util.Scanner;
public class Palindrome {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String word;
String inverse = "";
System.out.println("Write a sentence or word: ");
while (!input.hasNext("[A-Za-z]+")) {
System.out.println("Not valid! Try again: ");
input.nextLine();
}
word = input.nextLine();
word = word.replaceAll("\\s+","");
word = word.toLowerCase();
int length = word.length();
length = length - 1;
for (int i = length; i >= 0; i--) {
inverse = inverse + word.charAt(i);
}
if (word.equals(inverse)) {
System.out.println("Is a palindrome.");
} else {
System.out.println("Is not a palindrome.");
}
}
}
Basically when I enter a word or sentence I want it to check if it has any numbers anywhere in the input, if it has then you need to enter another one until it doesn't. Here is an example of output:
Write a sentence or word:
--> 11
Not valid! Try again:
--> 1 test
Not valid! Try again:
--> test 1
Is not a palindrome.
As you can see it works for most cases, but when I enter a word FIRST and then a space followed by a number it evaluates it without the number. I am assuming this is happening because in the while loop is checking for only input.hasNext but it should be input.hasNextLine I believe to check the entire string. However I cannot have any arguments if I do that. Help much appreciated!
Change your regex from: [A-Za-z]+ to ^[A-Za-z]+$ in order to prevent numbers anywhere in the input-string

Categories