Reputation: 25
I'm writing a simple Java program that asks the user to input a string, and then counts and displays the number of times each letter in the alphabet appears in that string. When I compile, I get this error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -25
at StringLetters.countLetters(StringLetters.java:43)
at StringLetters.main(StringLetters.java:23)
I have looked at other solutions to problems similar to mine, but none of them helped. Does anyone have any ideas? Thank you.
import java.util.Scanner;
public class StringLetters
{
public static void main(String[]args)
{
Scanner scan = new Scanner(System.in);
System.out.println("Please enter a string of words.");
String s = scan.nextLine();
int[] counts = countLetters(s.toUpperCase());
for(int i = 0; i < counts.length; i++)
{
if (counts[i] != 0)
{
System.out.println((char)('a' + i) + " appears " + counts[i] + ((counts[i] == 1) ? "time" : " times"));
}
}
}
public static int[] countLetters(String s)
{
int[] counts = new int[26];
for (int i = 0; i < s.length(); i++)
{
if(Character.isLetter(s.charAt(i)))
{
counts[s.charAt(i) - 'a']++;
}
}
return counts;
}
}
Upvotes: 0
Views: 6872
Reputation: 39437
In your argument String which you pass to the counting method, you have letters which are not lowercase English letters and that breaks your code.
In fact none of them are lowercase because you're calling s.toUpperCase()
and it seems you meant to call s.toLowerCase()
. Also, you need to filter out punctuation and any non-letter characters. You're already doing it here: if (Character.isLetter(s.charAt(i)))
.
So just change s.toUpperCase()
to s.toLowerCase()
and you'll be fine.
Upvotes: 2
Reputation: 4205
isLetter can return true in many case (have a look on its javadoc). In particular for uppercase character (peter>petrov is right, you probably don't want to convert to upper cases...)
I advice to implement a more basic test:
Char c = s.charAt(i);
if('a' <= c && c <= 'z')
{
counts[c - 'a']++;
}
else if('A' <= c && c <= 'Z')
{
counts[c - 'A']++;
}
Upvotes: 1
Reputation: 393771
Well, obviously the index in counts[s.charAt(i) - 'a']
gets above 25. It looks like you are assuming all your inputs would be lower case letters, even though you are passing to your countLetters
method an upper case String (countLetters(s.toUpperCase());
).
You should probably change it to counts[s.charAt(i) - 'A']
. Of course, that would only work for capital letters, but that's what you are currently passing to this method.
Upvotes: 2
Reputation: 2464
How do you account for capital letters? Seems like a good use for HashMap. Capital letters have a lower ASCII value than lower case letters. It looks like your index out of bounds is caused by a capital letter.
Upvotes: 0
Reputation: 61128
First, your issue - how do you deal with capital letters?
Obviously in your use case you do countLetters(s.toUpperCase())
then you do - 'a'
. This gives very odd results:
(int)'A' - (int)'a' = -25
(int)'Z' - (int)'a' = -7
An easier way to do this is using a Map
. With Java 8:
final Map<Character, Integer> counts = input.toUpperCase().chars().
collect(HashMap::new, (m, l) -> m.merge((char) l, 1, Integer::sum), Map::putAll);
Upvotes: 1