What is causing this StringIndexOutofBounds exception? - java

I have this code to find a palindrome below; I need to be able to remove all numbers, spaces, and punctuation from the user input String, so I've been using replaceAll. When I only had String input = str.toLowerCase(); and String newInput = input.replaceAll("[0-9]+", ""); in my code, there was no problem. It removes the numbers and continues. However when I try to add punctuation or a space, I get a StringIndexOutOfBoundsException.
Example: I input Anna.55
The line underneath all of the replaceAll statements, System.out.println(newestInput);, will print out anna but immediately throws the error when reaching the while loop and states that the problem is with the index of 6.
From my understanding (I am still learning Java and am unfamiliar with replaceAll) removing the spaces with replaceAll("\\s", "") would remove the spaces left by the previous replaceAll statements and thus there would be no index 6 (or even 4). How is there an error at index of 6 when it no longer exists?
import java.util.Scanner;
public class PalindromeTester {
public static void main (String[] args) {
String str;
String another = "y";
int left;
int right;
Scanner scan = new Scanner (System.in);
while (another.equalsIgnoreCase("y")) {
System.out.println("Enter a potential palindrome:");
str = scan.nextLine();
left = 0;
right = str.length() - 1;
String input = str.toLowerCase();
String newInput = input.replaceAll("[0-9]+", "");
String newerInput = input.replaceAll("\\W", "");
String newestInput = newerInput.replaceAll("\\s", "");
System.out.println(newestInput);
while (newestInput.charAt(left) == newestInput.charAt(right) && left < right) {
left++;
right--;
}
System.out.println();
if (left < right)
System.out.println("That string is not a palindrome.");
else
System.out.println("That string is a palindrome.");
System.out.println();
System.out.print ("Test another palindrome (y/n)? ");
another = scan.nextLine();
}
}
}

You're using right = str.length() - 1; to determine the length of the input, but you modify what was input after it (and what you compare)...
String input = str.toLowerCase();
String newInput = input.replaceAll("[0-9]+", "");
String newerInput = input.replaceAll("\\W", "");
String newestInput = newerInput.replaceAll("\\s", "");
System.out.println(newestInput);
while (newestInput.charAt(left) == newestInput.charAt(right) && left < right) {
Which means the String is no longer the original length, in your example, it's 1 character shorter
Instead, calculate the length of the newestInput instead
right = newestInput.length() - 1;
System.out.println(newestInput);
while (newestInput.charAt(left) == newestInput.charAt(right) && left < right) {

Two things first:
I think
input.replaceAll("\\W", "");
should be
newInput.replaceAll("\\W", "");
And right should be calculated after the tokens are removed and not before, like so:
left = 0;
String input = str.toLowerCase();
String newInput = input.replaceAll("[0-9]+", "");
String newerInput = newInput.replaceAll("\\W", "");
String newestInput = newerInput.replaceAll("\\s", "");
right = newestInput.length() - 1;
Otherwise right can be larger than the length of newestInput and you'll get a java.lang.StringIndexOutOfBoundsException.

Actually, an easier way to test if a string is a palindrome, is if it is the same backwards and forwards.

Related

How do you check if a string is a palindrome in java?

I am trying to write a program that checks if a string is a palindrome and so far I know I am on the right path but when I enter my code it keeps on running for ever. I don't know what the problem is and would like help finding out the solution. In my program I want the user to enter word or words in the method Printpalindrome and then the program should know if the string is a palindrome or not.
Here is my code:
...
Scanner console = new Scanner (System.in);
String str = console.next();
Printpalindrome(console, str);
}
public static void Printpalindrome(Scanner console, String str) {
Scanner in = new Scanner(System.in);
String original, reverse = "";
str = in.nextLine();
int length = str.length();
for ( int i = length - 1; i >= 0; i-- ) {
reverse = reverse + str.charAt(i);
}
if (str.equals(reverse))
System.out.println("Entered string is a palindrome.");
}
}
Because of this line:
n = in.nextLine();
your program is waiting for a second input, but you already got one before entering the function.
Remove this line and it works.
Here's your program, cleaned (and tested) :
public static void main(String[] args){
Scanner console = new Scanner (System.in);
String n = console.next();
Printpalindrome(n);
}
public static void Printpalindrome(String n){
String reverse = "";
for ( int i = n.length() - 1; i >= 0; i-- ) {
reverse = reverse + n.charAt(i);
System.out.println("re:"+reverse);
}
if (n.equals(reverse))
System.out.println("Entered string is a palindrome.");
else
System.out.println("Entered string is NOT a palindrome.");
}
Of course, this isn't the best algorithm, but you already know there are many QA on SO with faster solutions (hint: don't build a string, just compare chars).
Remove
Scanner in = new Scanner(System.in);
and
n = in.nextLine();
from Printpalindrome function
and it should work.
This can be implemented in a far more efficient manner:
boolean isPalindrom(String s){
if (s == null /* || s.length == 0 ?*/) {
return false;
}
int i = 0, j = s.length() - 1;
while(i < j) {
if(s.charAt(i++) != s.charAt(j--)) {
return false;
}
}
return true;
}
The argument for PrintPalindrom is ignored. You read another value with `in.nextLine()'. Which is the reason for your issues.
Ur code with some correction:-
import java.util.*;
class Palindrome
{
public static void main(String args[])
{
String original, reverse = "";
Scanner in = new Scanner(System.in);
System.out.println("Enter a string to check if it is a palindrome");
original = in.nextLine();
int length = original.length();
for ( int i = length - 1; i >= 0; i-- )
reverse = reverse + original.charAt(i);
if (original.equals(reverse))
System.out.println("Entered string is a palindrome.");
else
System.out.println("Entered string is not a palindrome.");
}
}
I tried your code and what i observed was that :
first of all you are making a string to enter on the line 2 of your code:
String n=console.next();
next the the program again goes to waiting when this line gets executed:
n = in.nextLine();
actually this particular line is also expecting an input so that is why the program halt at this point of time.
If you enter your String to be checked for palindrome at this point of time you would get the desired result .
But I would rather prefer you to delete the line
n = in.nextLine();
because, with this, you would have to enter two words which are ambiguous.

Hangman in Java throws ArrayIndexOutOfBounds

My programs throws StringIndexOutOfBoundsException at this segment of code: temp1 = temp.replace('-', temp.charAt(p)); I'm trying to get the index of the same letter (after comparing inputted letter and word) and removing the '-' to show that the user has guessed correctly.** **I've been trying for hours to no avail. I think the problem lies in my loops. Thanks for the answers :) if I violated anything, please forgive me.
run:
-----
Enter a letter:
a
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range:
3
at java.lang.String.charAt(String.java:658)
at Hangman.main(Hangman.java:34)
Java Result: 1
import java.util.Scanner;
public class Hangman {
public static void main (String [] args){
Scanner sc = new Scanner(System.in);
String word = "Sample";
String temp = null;
String temp1 = null;
String letter = null;
int n;
int m=0;
int p = 0;
for (n = 0; n<word.length(); n++){
temp = word.replaceAll(word, "-"); //replaces the String word with "-" and prints
System.out.print(temp);
}
while (m<=5){ //the player can only guess incorrectly 5 times
System.out.println("\nEnter a letter:");
letter = sc.nextLine();
letter.toLowerCase();
if (word.contains(letter) == true){
p = word.indexOf(letter);
temp1 = temp.replace('-', temp.charAt(p)); //if the word contains the letter, "-" is replaced by the letter.
System.out.print(temp1);
}
else {
System.out.print("\nMissed: "+letter); //if not, Missed: +the given letter
m++; //to count for incorrect guesses
}
System.out.print(temp1);
}
System.out.println("Game Over.");
}
}
When you do this:
temp = word.replaceAll(word, "-");
...you are setting temp to be just "-", and not (for example) "----". To see why, consider if word is "hello"; then this line looks like:
temp = "hello".replaceAll("hello", "-");
So then later you are assuming that temp is as long as word is, because you find an index in word and try to access that character in temp. But temp is only one character long, hence the exception.
p = word.indexOf(letter);
temp1 = temp.replace('-', temp.charAt(p));
Try this one.....
This will solve your problem...!!
package beans;
import java.util.Scanner;
public class Hangman {
public static String replace(String str, int index, char replace){
if(str==null){
return str;
}else if(index<0 || index>=str.length()){
return str;
}
char[] chars = str.toCharArray();
chars[index] = replace;
return String.valueOf(chars);
}
public static void main (String [] args){
Scanner sc = new Scanner(System.in);
String word = "Sample";
String temp = "";
String letter = null;
int n;
int m=0;
int p = 0;
for (n = 0; n<word.length(); n++){
temp = temp + word.replaceAll(word, "-"); //replaces the String word with "-" and prints
}
System.out.print(temp);
while (m <= 5){ //the player can only guess incorrectly 5 times
System.out.println("\nEnter a letter:");
letter = sc.nextLine();
letter.toLowerCase();
if (word.contains(letter) == true){
p = word.indexOf(letter);
temp = replace(temp, p , word.charAt(p)); //if the word contains the letter, "-" is replaced by the letter.
System.out.println(temp);
}
else {
System.out.print("\nMissed: "+letter); //if not, Missed: +the given letter
m++; //to count for incorrect guesses
}
}
System.out.println("Game Over.");
}
}
You shoud check documentation for replaceAll() method.Cause you are using it wrong.
replaceAll(String regex, String replacement)
Replaces each substring of this string that matches the given regular expression with the given replacement.
You putting whole string into regex parameter
If you do myString.replaceAll("\\.","-"); (use double backslash to specify regex) will replace any character beside newline with "-" check into regex. Regullar expressions
if (word.contains(letter) == true){
p = word.indexOf(letter);
temp1 = temp.replace('-', temp.charAt(p)); //if the word contains the letter, "-" is replaced by the letter.
System.out.print(temp1);
}
the word.indexOf(letter); return index of letter if that latter is present in string otherwise -1. that's why you are getting Exception.

Using methods to check for palindromes

I have to use methods to test a sentence for palindromes and I have got most of it done but it will only do the first word in the string and won't move on to the next one. I believe its something got to do with the spaces, if anyone could help that'd be great. Also I haven't studied arrays so I'd appreciate if arrays were not used.
class palindromeTesting
{
public static void main(String[] args)
{
String userInput;
String goodWords;
String palindromes;
System.out.println("Please enter a sentance to be tested for palindrome: ");
userInput = EasyIn.getString();
userInput += " " ;
goodWords = charsCheck(userInput); //Calling a method to check if any word contains more than letters.
palindromes = palinCheck(goodWords); //Checking the good words to see if they're palindromes.
System.out.println("The valid palindromes are " + palindromes);
} //Main
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
public static String charsCheck(String userInput)
{
String validWords;
String firstWord;
Boolean goodWord;
int spacePos;
char letter;
spacePos = userInput.indexOf(" ");
validWords = "";
while(spacePos > 0)
{
firstWord = userInput.substring(0 , spacePos);
goodWord = true;
for(int index = 0 ; index < firstWord.length() && goodWord == true ; index++)
{
spacePos = userInput.indexOf(" ");
letter = Character.toUpperCase(firstWord.charAt(index));
if(letter < 'A' || letter > 'Z' )
{
goodWord = false;
}
} //for
if(goodWord == true)
{
firstWord = firstWord + " ";
validWords = validWords + firstWord;
}
userInput = userInput.substring(spacePos + 1);
spacePos = userInput.indexOf(" ");
} //While
return validWords;
} //charsCheck main
//-----------------------------------------------------------------------------------------------------------------------------------------------------------
public static String palinCheck(String goodWords)
{
String firstWord;
String validPalins = "";
String backward = "";
int spacePos;
spacePos = goodWords.indexOf(" ");
while(spacePos > 0)
{
firstWord = goodWords.substring(0 , spacePos);
for(int i = firstWord.length()-1; i >= 0; i--)
{
backward = backward + firstWord.charAt(i);
}
if(firstWord.equals(backward))
{
validPalins = validPalins + firstWord;
}
goodWords = goodWords.substring(spacePos + 1) ;
spacePos = goodWords.indexOf(" ") ;
}//While
return validPalins;
} //palinCheck main
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
} //Class
If you believe the issue are spaces, you could always remove all spaces (and any other unwanted characters) with the replaceAll() method (check out the API). Say you have word1 and word2 you'd like to compare to see if they are palindromes, then do the following:
String word1 = "du mb";
String word2 = "b,mu d";
word1 = word1.replaceAll(" ", "");//replace it with empty string
word1 = word1.replaceAll(",", "");//even if the comma doesn't exist, this method will be fine.
word2 = word2.replaceAll(" ", "");
word2 = word2.replaceAll(",", "");
Once you've gotten ridden of unnecessary characters or spaces, then you should do the check. Also, you could always use Regex expressions for this kind of task, but that may be a bit difficult to learn for a beginner.
Also, I recommend using for loops (can probably be done in one for loop, but nested loops will do) instead of while loop for this task. Check out this example.
Sidenote:
Also I haven't studied arrays so I'd appreciate if arrays were not
used.
Strings are essentially char arrays.
The problem you described is actually not what is happening; your code does indeed move on to the next word. For my test, I used the test input Hi my name is blolb.
The problem is in your palinCheck method. You are using the backward variable to reverse the word and check whether it and firstWord, are equal. However, you aren't resetting the backward variable back to a blank string in the loop. As a result, you're constantly adding to whatever was in there before from the previous loop. At the end of the method, if I examine the content of backward using my test string above, it actually looks like iHymemansiblolb.
To solve this, simply declare String backward inside the while loop, like so:
while(spacePos > 0) {
String backward = "";
// rest of loop
Quick side note:
During the run of the palinCheck method, you're changing the goodWords parameter each iteration when you do this:
goodWords = goodWords.substring(spacePos + 1) ;
While this is technically acceptable (it has no effect outside of the method), I wouldn't consider it good practice to modify the method parameter like this. I would make a new String variable at the top of the method, perhaps call it something like currentGoodWords or something like that, and then change your line to:
currentGoodWords = goodWords.substring(spacePos + 1) ;
Also, I assume this is homework, so if you are allowed to use it, I would definitely take a look at the StringBuilder#reverse() method that Elliot Frisch mentioned (I admit, I never knew about this method before now, so major +1s to Elliot).
I had this code written as a personal project quite a while ago on palindrome using the shortest amount of code. It basically strip every non-word character, put it to lower case just with 13 lines. Hope this help haha! Let's hope other guys would get lucky to find this too.
import java.util.Scanner;
public class Palindrome {
public static void main(String[]args){
if(isReverse()){System.out.println("This is a palindrome.");}
else{System.out.print("This is not a palindrome");}
}
public static boolean isReverse(){
Scanner keyboard = new Scanner(System.in);
System.out.print("Please type something: ");
String line = ((keyboard.nextLine()).toLowerCase()).replaceAll("\\W","");
return (line.equals(new StringBuffer(line).reverse().toString()));
}
}

What's wrong with my Java code? It should count the spaces, but returns 0

The code is copied below. It should return the number of spaces if the character variable l is equal to a space, but always returns a 0.
I've tested it with letters and it worked, for example if I'm asking it to increment when the variable l is equal to e and enter a sentence with e in, it will count it. But for some reason, not spaces.
import java.util.Scanner;
public class countspace {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Enter a sentence:");
String str = input.next();
System.out.println(wc(str));
}
public static int wc(String sentence) {
int c = 0;
for (int i = 0; i < sentence.length(); i++) {
char l = sentence.charAt(i);
if (l == ' ') {
c++;
}
}
return c;
}
}
Scanner.next() (with the default delimited) is only parsing as far as the first space - so str is only the first word of the sentence.
From the docs for Scanner:
A Scanner breaks its input into tokens using a delimiter pattern, which by default matches whitespace.
Use nextLine instead. You can also print the line for debugging:
System.out.println(str);
Use String str = input.nextLine(); instead of String str = input.next();
This is the way you should do to get the next string.
You could have checked that str has the wrong value.

Write a program that allows the user to enter a string and then prints the letters of the String separated by comma

The output is always a String, for example H,E,L,L,O,. How could I limit the commas? I want the commas only between letters, for example H,E,L,L,O.
import java.util.Scanner;
import java.lang.String;
public class forLoop
{
public static void main(String[] args)
{
Scanner Scan = new Scanner(System.in);
System.out.print("Enter a string: ");
String Str1 = Scan.next();
String newString="";
String Str2 ="";
for (int i=0; i < Str1.length(); i++)
{
newString = Str1.charAt(i) + ",";
Str2 = Str2 + newString;
}
System.out.print(Str2);
}
}
Since this is homework I'll help you out a little without giving the answer:
If you want the output to only be inbetween letters IE: A,B,C instead of A,B,C, which is what I imagine you are asking about. Then you need to look at your for loop and check the boundary conditions.
The easiest way I see is :
public static void main(String[] args) {
Scanner Scan = new Scanner(System.in);
System.out.print("Enter a string: ");
String Str1 = Scan.nextLine();
String newString="";
String Str2 ="";
for (int i=0; i < Str1.length()-1; i++)
{
newString = Str1.charAt(i) + ",";
Str2 = Str2 + newString;
}
Str2 = Str2 + Str1.charAt(Str1.length()-1);
System.out.println(Str2);
}
The output it will give is :
run:
Enter a string: Hello world
H,e,l,l,o, ,w,o,r,l,d
BUILD SUCCESSFUL (total time: 5 seconds)
Though I will highly recommend learning regular expression as suggested by #Roman. Till then this will do the trick. :)
Try regular expressions:
String input = scanner.next();
String output = input.replaceAll(".", "$0,");
With spaces it would be a bit easier since you don't need to abandon last 'odd' comma:
output = output.substring (0, ouput.length() - 2);
When you've figured out the loop-solution, you could try the following ;)
System.out.println(Arrays.toString("HELLO".toCharArray()).replaceAll("[\\[ \\]]", ""));
Just don't append the comma when the last item of the loop is to be appended. You have the item index by i and the string length by Str2.length(). Just do the primary school math with a lesser-than or a greater-than operator in an if statement.
The following snippet should be instructive. It shows:
How to use StringBuilder for building strings
How to process each char in a String using an explicit index
How to detect if it's the first/last iteration for special processing
String s = "HELLO";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (i == 0) { // first
sb.append("(" + ch + ")");
} else if (i == s.length() - 1) { // last
sb.append("<" + ch + ">");
} else { // everything in between
sb.append(Character.toLowerCase(ch));
}
}
System.out.println(sb.toString());
// prints "(H)ell<O>"

Categories