Java: for loop crashing using string charAt method - java

I have a bug in this block of code. The debugger suggest it´s cause is this line of code char chr = getSecretWord.charAt(i);
What this code does is look for a match between userInput and secretWord. I have the for loop to go through the length of the secretWord letters one by one, and if there is a letter matching return true. If not, return false... but the program crashes when it is suppose to just return false... I guess it is something with this line, but do not know exactly what getSecretWord.charAt(i);
private boolean isMatchingSecretWord(String userInput)
{
String secretWord = "";
String getSecretWord = getSecretWord();
for (int i = 0; i <= getSecretWord.length();i++)
{
char chr = getSecretWord.charAt(i);
secretWord = ""+chr;
if (secretWord.equals(userInput))
{
println("is true");
return true;
}
}
return false;
}
As an side note, is what I´ve done with this code correct, assigning the getSecretWorld() Method to a String so I can use the Strings method length()?
String getSecretWord = getSecretWord();
for (int i = 0; i <= getSecretWord.length();i++)
Debug code:
Exception in thread "Thread-4" java.lang.StringIndexOutOfBoundsException: String index out of range: 4
at java.lang.String.charAt(String.java:686)
at Hangman.isMatchingSecretWord(Hangman.java:49)
at Hangman.userInput(Hangman.java:34)
at Hangman.run(Hangman.java:20)*

for (int i = 0; i <= getSecretWord.length(); i++)
should be:
for (int i = 0; i < getSecretWord.length(); i++)
// ^^^
// see here
The valid indexes for an n-character string (or an n-element array) are 0 through n-1 inclusive.
So, if your secret word is xyyzy, the valid indexes are zero through four. Your original loop iterates with i set to zero through five, hence the problem.
But there seems to be a lot of unnecessary code in there, when you could get away with something simple.
First, I would remove a source of confusion - the function name sounds like the user input and the secret word have to match completely whereas your comment indicates otherwise:
Thanks, this works. But the reason for the loops is that the user enters one letter, I want to see if that letter is within the SecretWord. (it´s a hangman game).
In that case, you simply want to see if the single character exists in the secret word. I would change the function name to suit and, even then, it can be done with a lot less code:
private boolean isInSecretWord (String userInput) {
String secretWord = getSecretWord();
return secretWord.contains(userInput);
}

You were getting out of bounds error as your for loop wasn't looping correctly, I have modified it so that the loop doesn't go out of bounds and also your secretWord variable wasn't populating correctly, the code should now work as intended :)
private boolean isMatchingSecretWord(String userInput)
{
String secretWord = "";
String getSecretWord = getSecretWord();
for (int i = 0; i < getSecretWord.length();i++)
{
char chr = getSecretWord.charAt(i);
secretWord = secretWord + chr;
if (secretWord.equals(userInput))
{
println("is true");
return true;
}
}
return false;
}

Related

Using Scanner to analyse a string, letter by letter, in a for loop (Throwing IndexOutOfBoundExceptions)

I need to count the frequency at which a letter appears in a string.
To do this, I thought about using a scanner object, passing the string to it
Scanner s = new Scanner(String)
and using the next() method to analyse each char with a switch statement.
I've done a search on these boards and have devised the following :-
for (int i = 0; i < outputString.length(); i++) {
Scanner s = new Scanner(outputString);
char letter = s.next().charAt(i);
switch (letter) {
switch code;
}
This appears to work when the string I'm analysing contains anything (-_z1 etc..) other than whitespaces which will cause the program to throw a String.IndexOutOfBoundException (4).
Is there something else I can try or should I just remove all the whitespaces from the word (i.e. I'm thinking by creating a newword string using a for loop to add each string.charAt(i) != ' ').
Edit: I forgot that the scanner was in the for loop, I'll take it out. Secondly, not sure if it changes matters but I'm trying to count the no of times each letter in the alphabet in the string appears, not just one type of letter. Thanks for your comments!
Thanks in advance,
Here is an alternative way to solve this problem provided on another question. (can't leave comments yet.. so have to put as an answer...)
How to count frequency of characters in a string?
While having this:
Scanner s = new Scanner(outputString);
Inside the for loop, you're creating a new Scanner in every iteration (not efficient nor what you want).
If you already have a String called outputString you can access its characters / letters directly as follows:
for (int i = 0; i < outputString.length(); i++) {
char letter = outputString.charAt(i);
//The rest of you code here
}
I strongly think you're complicating things by using that approach. You can simply pass the String (and the char you are searching for) into a method just like the one below:
public int checkFreq(char letter, String word){
int freq = 0;
for(int i = 0; i < word.length(); i++){
if((word.charAt(i)) == letter){
freq++;
}
}
return freq;
}
I hope this helps.. Merry coding!
You should follow the above solution for getting repeated characters in a string. However, I will just give you a hint about why you are getting the exception
consider the following code:
String outputString = "Pre ";
for (int i = 0; i < outputString.length(); i++) {
Scanner s = new Scanner(outputString);
System.out.println(outputString.length()); // output is 4
System.out.println(s.next().length()); //output is 3, not considering the space
//char letter = s.next().charAt(i);
//System.out.println(letter);
}
First of all, you shold not create new Scanner each time when you ready next character. Do it only once, before for loop.
Second - to read scanner character by character, you have set delimeter as "". In this case, scan.next() returns next character.
Third - you use Scanner to analyze string, that's OK (not optimal and overhead, but OK). Then do create new Scanner isntance and rely on it's data, but not on length of the goven string; do use Scanner.hasNext() method. I mean that all you need, is just add hasNext() to be sure that more characters exists in the scanner's stream:
try (Scanner scan = new Scanner(outputString)) {
scan.useDelimiter(""); // to make scan.next() return one single character
while (scan.hasNext()) {
char ch = scan.next().charAt(0); // next() returns String with one character
// do your work
}
}
P.S. This is code examples, how you can cound character frequencey in the given string with different ways. Probably, one of them you'll find more relevant to your task.
// this is your approach
public static int characterFrequency(String str, char ch) {
try (Scanner scan = new Scanner(str)) {
scan.useDelimiter("");
int count = 0;
while (scan.hasNext())
count += scan.next().charAt(0) == ch ? 1 : 0;
return count;
}
}
// this one is the most efficient
public static int characterFrequency(String str, char ch) {
int count = 0;
for (int i = 0; i < str.length(); i++)
count += str.charAt(i) == ch ? 1 : 0;
return count;
}
// this one is the smallest of code
public static int characterFrequency(String str, char ch) {
return (int)str.chars().filter(e -> e == ch).count();
}

The Creation of The Encryption Key for a Keyword Cipher in My Code (Java)

I was just wondering if I could get some help with a question involving keyword ciphers.
The following code is supposed to create the encryption key for a keyword cipher (the key that states how your input (let's say "this is a secret message") became ("qabp bp k poynoq hoppkdo")). The key is, therefore, a String or char array. My teacher had us use a char array. For the case above, the key would {KEYWORDABCFGHIJLMNPQSTUVXZ}, and the basic alphabet would correspond to this {ABCDEFGHIJKLMNOPQRSTUVWXYZ}, therefore A would become K, I would become A, and so on and so forth.
But, anways, back to the problem at hand, when I try to create the key, the first loop that you see below works perfectly fine adding in the keyword for the first values of the array; however, after this adding in the rest of the array (the rest of the alphabet not including or skipping the letters of the keyword) doesn't seem to work in the second loop.
I don't exactly know what I am doing wrong, but I would guess it would have to do with one of the if statements, or the java keyword (continue;) that I use in the loop. Because it appears that when I print the keyword array, it comes out to {KEYWORDABCDEFGHIJKLMONPQRS} leaving out the last seven letters of the alphabet instead of the letters that already occur in the word, KEYWORD.
If you could help fix the code, or get me on the right track, that would be much appreciated. If you have an question on the question, fell free to ask in the comment section below/
Thank you so much for all your help!
public class Crytograph
{
private String in;
private String out;
//private int awayFrom;
private char [] keyword;
private String word;
public Crytograph(String input, String wordLY) // , int fromAway )
{
in = input.toLowerCase();
out = "";
awayFrom = fromAway;
word = wordLY;
keyword = new char[26];
int counter = 97;
int counter1 = 0;
for (int x = 0; x < word.length(); x++)
{
keyword[x] = word.charAt(x);
}
for (int i = word.length(); i < 26; i++)
{
if ((char)(counter) == keyword[counter1])
{
continue;
}
else
{
keyword[i] = (char)(counter);
//System.out.println(keyword[i]);
}
counter++;
counter1++;
if (counter1 == word.length())
{
counter1 = 0;
}
}
}
You're comparing each new character to a single character at index counter1. But you really need to compare it to all the characters in word. Even if you happen to find a match, continue; will still increment i, meaning your array will be missing one or more characters at the end. Try this instead:
char c = 'a' - 1;
for (int i = word.length(); i < 26; i++) {
// loop until we find a char not contained in `word`
while (word.contains(String.valueOf(++c)));
keyword[i] = c;
}

Decryption code not changing actual data

I am having issues running my code correctly. I created a decryption method that is supposed to take a word and replace every 2 letters with each other. Unless the word is an odd amount, then I should leave the last letter alone. The issue is that I am only printing out the letters and not changing the actual data of the string.
static String ezDecrypt (String ezEncrypt){
//this variable holds the value of the String's length
int cl = ezEncrypt() ;
//if the length of the String is even then do this
if (ezEncrypt.length() % 2 == 0){
//for loop that begins at 0
//keeps looping until it reaches the end of the string
//each loop adds 2 to the loop
for(int i = 0; i < cl; i= i + 2) {
//will print out the second letter in the string
System.out.print(ezEncrypt.charAt(i + 1));
//will print out the first letter in the string
System.out.print(ezEncrypt.charAt(i));
}
}
//if the length of the word is an odd number, then
else if(ezEncrypt.length() % 2 != 0){
//loop through and do the same process as above
//except leave this loop will skip the last letter
for(int i = 0; i < cl-1; i= i + 2) {
//will print out the second letter in the string
System.out.print(ezEncrypt.charAt(i + 1));
//will print out the first letter in the string
System.out.print(ezEncrypt.charAt(i));
}
}
return ezEncrypt;
}
I understand you're trying to modify a String in order to decrypt it. Well, I got some news for you: the String class in java has been designed in such a way String objects are immutable. That means you can't alter their contents once you have created them. But don't worry, there are other ways to achieve what you have in mind.
For instance, you can get an array of chars from the received object by calling ezEncrypt.toCharArray(); you can modify the contents of an array so you will have to work with that, swapping the characters just like you're supposed to. Then, once the decryption is done, create another String object by using the constructor new String(char[] chars), passing your array as argument, and return it.
Something more or less like this:
static String ezDecrypt (String ezEncrypt){
//this variable holds the value of the String's length
int cl = ezEncrypt.length();
//an array holding each character of the originally received text
char[] chars = ezEncrypt.toCharArray();
//temporary space for a lonely character
char tempChar;
//Do your swapping here
if (ezEncrypt.length() % 2 == 0){ //Length is even
//for loop that begins at 0
//keeps looping until it reaches the end of the string
//each loop adds 2 to the loop
for(int i = 0; i < cl; i = i + 2) {
tempChar = chars[i];
chars[i] = chars[i+1];
chars[i+1] = tempChar;
}
} else { //Length is odd
//loop through and do the same process as above
//except leave this loop will skip the last letter
for(int i = 0; i < cl - 1; i = i + 2) {
tempChar = chars[i];
chars[i] = chars[i+1];
chars[i+1] = tempChar;
}
}
return new String(chars);
}
Hope this helps you.
Strings are immutable, so calling a method on the string will not change the string. It will only return a value derived from the string. You need to make a new empty string and start adding the return values to it character by character.

How do you find the amount of times a single character appears in a string and then store it into another string?

here is the code I have right now:
String dog = "my!cat!is!brown!so!what!";
String temp = "";
for(int i = 0; i <= dog.length(); i++) {
if(dog.charAt(i) == '!') {
temp+= "a";
}
}
I am trying to get it to the point where I can print "6" As and I don't know if I am heading in the wrong direction. Not asking for code just tips thanks.
I would try to create a counter prior to your for loop. Then on every occurence of the char you are looking for, increment the counter.
int j = 0; //Don't use i since it is your loop counter
//Each occurence:
j++;
Then convert that int counter to your string object when the loop is complete.
int count = StringUtils.countOccurrencesOf(dog, dog[i]);
if(temp.indexOf(dog[i])==-1)
{
temp+=dog[i]+": "+count+",";
}

piglatin translator java

I am working on a pig latin translator which translator the given word into pig latin. Here is the pig latin method and the isVowel method.
public static void pigLatin(String s) {
char[] array = s.trim().toCharArray();
if(isVowel(s.charAt(0)) && !Character.toString(s.charAt(0)).equalsIgnoreCase("y")){
System.out.println(s+"way");
}else {
int i = 0;
String toReturn = "";
do {
toReturn += array[i];
i++;
}while(!isVowel(s.charAt(i)) && !Character.toString(array[i]).equalsIgnoreCase("y"));
System.out.println(s.substring(i)+toReturn+"ay");
}
}
public static boolean isVowel(char c) {
char[] vowels = new char[] {'a','e','i','o','u','y'};
for(int i = 0;i<vowels.length;i++) {
if(Character.toString(vowels[i]).equalsIgnoreCase(Character.toString(c))) {
return true;
}
}
return false;
}
The problem is when I input words "BIrD" and "quiet". First one throws java.lang.StringIndexOutOfBoundsException: String index out of range: 4
The second one doesn't convert properly. Quiet prints uietqay, when it supposes to be ietquay, but that doesn't make sense because, you supposed to take all constants upto the vowel, which should mean uietquay so why is it ietquay? Can someone please point me in the correct direction?
NOTE: This is not homework.
Ignoring case, Is that a "BLRD" or a "bird"? Because if it has no vowels, your do-while loop doesn't terminate except by going out of bounds.
Your second case, "quiet" should be "uietqay" unless you want to add special logic to keep "qu" together. You could accomplish this in your while condition by making it uglier:
while( (!isVowel(s.charAt(i)) || isQU(s, i)) && !Character.toString(array[i]).equalsIgnoreCase("y"))
And then implement the appropriate isQU(String s, int index).
But I'd suggest that a little more rewriting is in order to make your code more readable. As is, I'm not quite sure why your isVowel checks for "y" and your while condition also checks for "y". Some of the time you use array[i] and some of the time you use charAt(i). This inconsistency makes your code harder to read with little or no benefit.
public static String pigLatin(String a){
a=a.toLowerCase();
String [] x=a.split(" ");
int vowl=0;
String c="";
String d="";
String trans="";
for(int i=0; i<x.length; i++){
for(int j = 0;j<x[i].length();j++){
if(x[i].charAt(j)=='a'||x[i].charAt(j)=='e'||x[i].charAt(j)=='i'||x[i].charAt(j)=='o'||x[i].charAt(j)=='u'){
vowl=j;
j=x[i].length();
}
}
c=x[i].substring(0,vowl);
d=x[i].substring(vowl,x[i].length());
trans+= d+c+"ay ";
}
return trans;
}

Categories