why does my program loop infinitely? - java

My spell checking program doesn't give any error codes, just spell-checks the same words over and over, infinitely.
Is there a way to stop this infinite loop and put a cap on how many words it checks, for example, to end the code when ten incorrect words have been corrected?
I'm almost certain that the infinite loop is a result of this method here:
public static void SpellChecker() throws IOException {
dictionary = new Hashtable<String, String>();
System.out.println("Searching for spelling errors ... ");
try {
// Read and store the words of the dictionary
BufferedReader dictReader = new BufferedReader(new FileReader("dictionary.txt"));
while (dictReader.ready()) {
String dictInput = dictReader.readLine();
String[] dict = dictInput.split("\\s"); // create an array of
// dictionary words
for (int i = 0; i < dict.length; i++) {
// key and value are identical
dictionary.put(dict[i], dict[i]);
}
}
dictReader.close();
String user_text = "";
// Initializing a spelling suggestion object based on probability
SuggestSpelling suggest = new SuggestSpelling("wordprobabilityDatabase.txt");
// get user input for correction
while (!user_text.equalsIgnoreCase("q")) {
// CleanString is a string full of words to be spell checked
user_text = cleanString;
String[] words = user_text.split(" ");
int error = 0;
for (String word : words) {
suggestWord = true;
String outputWord = checkWord(word);
if (suggestWord) {
System.out.println("Suggestions for " + word +
" are: " + suggest.correct(outputWord) + "\n");
error++;
}
}
if (error == 0 & !user_text.equalsIgnoreCase("q")) {
System.out.println("No mistakes found");
}
}
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}

You never ask the user if he/she wants to quit or not, from inside the while loop. So user_text is initialized with cleanString, and never changes inside the loop, hence the infinite loop.

Related

Using boolean to exit loops and then redo the loops

I'm fairly new to Java, so I don't know too many fancy stuff and I'm kind of stuck.
What I need to do is, take a text file; import the content into an ArrayList; check each line for a specific Char that is between two "#"; then check each line in the ArrayList again to see if one of the lines already has that Char; if it does, then I need to re-enter the whole String line and re-check it; and if it doesn't, then I need to put it at the bottom of the ArrayList and into the text file.
So far, I've gotten to the part where I need to check if the entered line's Char is repeating, but I can only do it once. If, for example, I enter it again I would get an IndexOutOfBoundsException because of one of the loops. So, I figured I'd use a boolean to exit the loops and re-enter them, but unfortunately, after entering the whole String once, it asks me to do it again in order to repeat the process because I'm exiting and entering the wrong loop, but I can't seem to figure out which.
ArrayList<String> Prices = new ArrayList<String>();
try (BufferedReader br = new BufferedReader (new FileReader("file.txt"))){
String CurrentLine;
while ((CurrentLine = br.readLine()) != null){
Prices.add(CurrentLine);
}
}catch (IOException e) {
e.printStackTrace();
}
boolean CheckSequence = true;
boolean Redo = false;
String StringArrayPrices[] = new String[Prices.size()];
Scanner sc = new Scanner (System.in);
while (CheckSequence == true){
System.out.println("Insert product in the following format, 'Product#Letter#Number': ");
String ProductString = sc.nextLine();
char ProductArray[] = ProductString.toCharArray();
for (int i = 0; i < Prices.size(); i++){
StringArrayPrices[i] = Prices.get(i);
char CharArrayPrice[] = StringArrayPrices[i].toCharArray();
for (int j = 0; j < CharArrayPrice.length && Redo == false; j++){
if (CharArrayPrice[j] == '#' && CharArrayPrice[j+2] == '#'){
char TemporaryLetter = CharArrayPrice[j];
for (int k = 0; k < ProductArray.length && Redo == false; k++){
if (ProductArray[k] == '#' && ProductArray[k+2] == '#'){
char TemporaryLetter2 = ProductArray[k];
if (TemporaryLetter == TemporaryLetter2){
System.out.println("The letter is repeating. Enter product again or exit by writing '-1': ");
ProductString = sc.nextLine();
if (ProductString == "-1"){
CheckSequence = false;
}
Redo = true;
}
if (TemporaryLetter != TemporaryLetter2){
Prices.add(ProductString);
}
}
}
}
}
}
}
Right now, when I re-enter the String, I'm greeted with the first message ""Insert product in the following format, 'Product#Letter#Number': "", instead of the ""The letter is repeating. Enter product again or exit by writing '-1': "".
The first line should only show up when I'm entering a completely new String instead of when the previous one's repeating.
I hope I didn't make this too confusing.
All of the loops is not the way to go.
I'm not entirely sure of the requirement, but I think this meets it.
Note that you should probably define a Product class to encapsulate much of this.
List<String> prices;
Set<String> letters;
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
prices = reader.lines.collect(Collectors.toList());
}
letters = prices.stream.map(p -> getLetter(p)).collect(Collectors.toSet());
Scanner scanner = new Scanner(System.in);
boolean shouldContinue = true;
while (shouldContinue) {
System.out.println("Enter Product");
String product = scanner.nextLine();
if (product.equals("-1")) {
shouldContinue = false;
} else {
String letter = getLetter(product);
if (letters.contains(letter) {
System.out.println("Repeat. Re-enter");
} else {
prices.add(product);
letters.add(letter);
}
}
}
with the helper
private String getLetter(String s) {
return s.split("#")[1]; //Or use the appropriate regex to extract the letter.
}
which could use some error handling.
To avoid java 8's streams, You can use the same code you used in the question to build prices and
Set<String> letters = new HashSet<>();
for (String price : prices) {
letters.add(getLetter(price));
}

Word count function that counts words in a txt file

I'm very new to java here so please bear with me.
I'm currently trying to create code that does the following:
Add code to your processFile function that counts the number of times each word appears in the file.
Add code to your processFile function that loops through your HashMap to find the most frequent word. After your loop, the variable added for bonus requirement #1 should contain the value for the most frequent word.
So far I've come up with this and was wondering if anyone could please help me progress further.
Map<String, Integer> freq = new Hashmap<String, Integer>();
FileInputStream fi = new FileInputStream("readwords,txt");
Scanner input = new Scanner(fi);
while (input.hasNext()) {
String word = input.next().toLowerCase();
Integer f = freq.get(word);
if (f == null) {
freq.put(word,1);
}
else {
freq.put(word,f+1);
}
}
Thank you
Your syntax is close, but you've mixed String declaration styles, your generic type is missing a > and your variable names are inconsistent. I think you wanted something like,
Map<String, Integer> map = new HashMap<>();
File file = new File("readwords.txt");
try (Scanner input = new Scanner(file)) {
while (input.hasNext()) {
String word = input.next().toLowerCase();
Integer f = map.get(word);
if (f == null) {
map.put(word, 1);
} else {
map.put(word, f + 1);
}
}
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
}
For counting the words and for getting most frequently used word you can try this:
public void processFile() throws Exception {
Map<String, Integer> freq = new HashMap<>();
FileInputStream fi = new FileInputStream("readwords.txt");
String mostFreqWord = null;
Integer highestFreq = 0;
Scanner input = new Scanner(fi);
while (input.hasNext()) {
String word = input.next().toLowerCase();
Integer f = freq.get(word) == null ? 1 : freq.get(word) + 1;
freq.put(word, f);
if(f > highestFreq) {
mostFreqWord = word; // set most frequent word
highestFreq = f; // frequency of most frequent word
}
}
System.out.println("Word :" + mostFreqWord
+ " is the most frequent word with frequency:" + highestFreq);
}
Since I have modified the code you already posted, here is the explanation of modification that I did (I assume that you already know what your original code was doing).
Inside loop, below line checks if word word has encountered first time in loop, if yes then sets it's frequency as 1 otherwise it increments frequency for that word.
Integer f = freq.get(word) == null ? 1 : freq.get(word) + 1;
Then it sets latest frequency for the word: freq.put(word, f);
Statement if(f > highestFreq) checks if the highest frequency is still highest, if not then updates highestFreq and mostFreqWord words.

Issue iterating through two arraylists

EDIT: Thanks so much for all the really quick feedback. Wow. I did just paste it all for you instead of just those two for loops. Thanks.
This may have been totally answered before. I have read SO for the last few years but this is my first post. I have been using the site and others to help solve this so my apologies in advance if this has been answered!
I am iterating through two arraylists. One is derived from user input; the other is a dictionary file converted into an arraylist. I am trying to compare a word in the input with a dictionary word. The input list and the dictionary list are valid and if I simply iterate through them, they contain what they should (so that isn't the issue. I assume my issue is somewhere with how I am handling the iteration. I'm a fairly novice Java programmer so please go easy on me.
Thanks
public String isSub(String x) throws FileNotFoundException, IOException {
//todo handle X
String out = "**********\nFor input \n" + x + "If you're reading this no match was found.\n**********";
String dictionary;
boolean solve = true;
/// Get dictionary
dictMaker newDict = new dictMaker();
dictionary = newDict.arrayMaker();
List<String> myDict = new ArrayList<String>(Arrays.asList(dictionary.split(",")));
List<String> input = new ArrayList<String>(Arrays.asList(x.split(" ")));
List<String> results = new ArrayList<String>();
//results = input;
String currentWord;
String match = "";
String checker = "";
String fail="";
//Everything to break sub needs to happen here.
while (solve) {
for(int n = 0; n < input.size(); n++) { //outside FOR (INPUT)
if(!fail.equals("")) results.add(fail);
checker = input.get(n).trim();
for(int i = 0; i < myDict.size(); i++) { //inside FOR (dictionary)
currentWord = myDict.get(i).trim();
System.out.print(checker + " " + currentWord + "\n");
if(checker.equals(currentWord)) {
match = currentWord;
results.add(currentWord);
fail="";
} //end if
else {
fail = "No match for " + checker;
}
}//end inside FOR (dictionary)
} //END OUTSIDE FOR (input)
solve=false;
} //end while
out = results.toString();
return out;
}
Output results for input "test tester asdasdfasdlfk"
[test, No match for test, tester, No match for tester]
Carl Manaster gave the correct explanation.
Here's an improved version of your code:
for (int n = 0; n < input.size(); n++) { //outside FOR (INPUT)
String checker = input.get(n).trim();
boolean match = false;
for (int i = 0; i < myDict.size(); i++) { //inside FOR (dictionary)
String currentWord = myDict.get(i).trim();
System.out.print(checker + " " + currentWord + "\n");
if (checker.equals(currentWord)) {
match = true;
results.add(currentWord);
break;
} //end if
} //end inside FOR (dictionary)
if (!match) {
results.add("No match for " + checker);
}
} //END OUTSIDE FOR (input)
Also, consider using a HashMap instead of an ArrayList to store the dictionary and trim the words when you store them to avoid doing it in each pass.
It looks as though every word in input gets compared to every word in your dictionary. So for every word that doesn't match, you get a fail (although you only write the last failure in the dictionary to the results). The problem appears to be that you keep looping even after you have found the word. To avoid this, you probably want to add break to the success case:
if (checker.equals(currentWord)) {
match = currentWord;
results.add(currentWord);
fail = "";
break;
} else {
fail = "No match for " + checker;
}
If you are using a dictionary, you should get it with keys not with index. So it should be
if(myDict.containsKey(checker)){
String currentWord =myDict.get(checker);
System.out.print(checker + " " + currentWord + "\n");
match = currentWord;
results.add(currentWord);
fail = "";
}
else {
fail = "No match for " + checker;
}
I think more or less your code should like following.
ArrayList<String> input= new ArrayList<String>();
input.add("ahmet");
input.add("mehmet");
ArrayList<String> results= new ArrayList<String>();
Map<String, String> myDict = new HashMap<String, String>();
myDict.put("key", "ahmet");
myDict.put("key2", "mehmet");
String match="";
String fail="";
for (int n = 0; n < input.size(); n++) { //outside FOR (INPUT)
if (!fail.equals(""))
results.add(fail);
String checker = input.get(n).trim();
for (int i = 0; i < myDict.size(); i++) { //inside FOR (dictionary)
// String currentWord = myDict.get(i).trim();
if(myDict.containsKey(checker)){
String currentWord =myDict.get(checker);
System.out.print(checker + " " + currentWord + "\n");
match = currentWord;
results.add(currentWord);
fail = "";
}
else {
fail = "No match for " + checker;
}
} // end inside FOR (dictionary)
} // end outside FOR (input)
// solve = false; I dont know what is this
//} //end while. no while in my code
return results.toString();
You should place the dictionary to a HashSet and trim while add all words. Next you just need to loop the input list and compare with dict.conatins(inputWord). This saves the possible huge dictionary loop processed for all input words.
Untested brain dump:
HashSet<String> dictionary = readDictionaryFiles(...);
List<String> input = getInput();
for (String inputString : input)
{
if (dictionary.contains(inputString.trim()))
{
result.add(inputString);
}
}
out = result.toString()
....
And a solution similar to the original posting. The unnecessary loop index variables are removed:
for (String checker : input)
{ // outside FOR (INPUT)
fail = "No match for " + checker;
for (String currentWord : myDict)
{ // inside FOR (dictionary)
System.out.print(checker + " " + currentWord + "\n");
if (checker.equals(currentWord))
{
match = currentWord;
results.add(currentWord);
fail = null;
break;
}
} // end inside FOR (dictionary)
if (fail != null)
{
results.add(fail);
}
} // end outside FOR (input)
solve = false;
return results.toString();
The trim should be made while add the elements to the list. Trim the dictionary values each time is overhead. And the inner loop itself too. The complexity of the task can be reduced if the dictionary data structure is changed from List to Set.
Adding the result of "fail" is moved to the end of the outer loop. Otherwise the result of the last input string is not added to the result list.
The following code is terrible:
else {
fail = "No match for " + checker;
}
The checker does not change within the dictionary loop. But the fail string is constructed each time the checker and the dictionary value does not match.

Not sure why array goes out of bounds JAVA

I'm getting an Array Index Out of Bounds exception on the String weapon = dataz[1]; line at runtime. I'm not sure what is causing this as this is nearly the same code I've used on previous assignments. Any logic as to why this is happening would be greatly appreciated!
public Hero[] getHeroes(){
String file = getFilePath();
Hero[] heroPower = new Hero[5];
int i=0;
try{
Scanner data = new Scanner(file);
while(data.hasNextLine() && i < 5)
{
String next = data.nextLine();
if(!next.trim().isEmpty())
{
String[] derp = next.split(",");
String name = derp[0];
String weapon = derp[1];
int attackPoints = Integer.parseInt(derp[2]);
heroPower[i] = new Hero(name,weapon,attackPoints);
i++;
}
}
data.close();
} finally {
}
return heroPower;
}
}
Your next string probably doesn't split. It doesn't have a , and you're not checking for that option.
Your code processes empty lines correctly, but it fails when the input does not have at least three tokens: it assumes that derp[0], derp[1], and derp[2] are valid, but the validity depends on the input.
You can fix it by checking the number of tokens that you get back from next.split:
String next = data.nextLine();
String[] derp = next.split(",");
if(derp.length >= 3) {
...
}
This condition also covers the situation when the trimmed next is empty, so a separate check is not required.
You really need to make sure that the number of inputs you are inputting is the number of inputs you are expecting, a simple check would be to check the number of arguments in the derp array that you get from split.
public Hero[] getHeroes(){
String file = getFilePath();
Hero[] heroPower = new Hero[5];
int i=0;
try{
Scanner data = new Scanner(file);
while(data.hasNextLine() && i < 5)
{
String next = data.nextLine();
if(!next.trim().isEmpty())
{
String[] derp = next.split(",");
//This is the line to change
if(derp > 3){
String name = derp[0];
String weapon = derp[1];
int attackPoints = Integer.parseInt(derp[2]);
heroPower[i] = new Hero(name,weapon,attackPoints);
i++;
}else{
//throw an error
}
}
}
data.close();
} finally{
}
return heroPower;
}
}
The problem is most likely your input, it doesn't contain any , symbols:
String[] derp = next.split(","); // split by commas a word that has no commas so derp.length == 1
String name = derp[0]; // this is ok since length is 1
String weapon = derp[1]; // this is error
You should check derp.length before using it:
String[] derp = next.split(",");
if(!derp.length == 3) { // because name=derp[0], weapon=derp[1], attackPoints = derp[2]
// ... create name, weapon, points and assign to heroPower
} else {
System.out.println("Invalid input");
}

Reading from an array list and comparing to an input string

Basically I have been asked to create a small letters game in which the user picks some vowels and consonants and these are added to an array list, once that has happened, we have to print out the contents of the array list e.g. it could look like this, [T,S,I,L,Y,A,R,R,A] and then we prompt the player to input what words they think they can make from the given list of characters. What I am looking for some pointers on is how to make sure the user can only use they characters and also how to compare their answer to a dictionary file. The only code I have so far is reading in my dictionary file. Any help would be greatly appreciated.
try {
BufferedReader reader = new BufferedReader(new FileReader("dictionary.txt"));
String line = reader.readLine();
List<String> words = new ArrayList<String>();
while (line != null) {
String[] wordsLine = line.split(" ");
for (String word : wordsLine) {
words.add(word);
}
line = reader.readLine();
}
System.out.println("Here is your board again: " + genString + "\n");
System.out.println("Please enter your answer!\n");
} catch (Exception e) {
System.out.println(e);
}
genString is my, what would be the list of characters and I have still to place the scanner in for user input.
The basic idea is putting the characters from user input into some collection, then iterating over the characters of the word and checking against that collection.
Finally, if everything is kosher, look up the word in the dictionary.
List<Character> charsFromUser = new LinkedList<Character>();
Set<String> dictionary = new HashSet<String>();
boolean illegalCharUsed = false;
boolean done = false;
String wordFromUser = null;
// dictionary = // fill dictionary
// charsFromUser = // get chars from user
// wordFromUser = // get word from user
for (int i = 0, l = wordFromUser.length(); i < l && !illegalCharUsed; ++i) {
char c = wordFromUser.charAt(i);
if (!charsFromUser.contains(c)) {
illegalCharUsed = true;
} else {
charsFromUser.remove(Character.valueOf(c)); // remove this line if
// users may reuse letters
}
}
if (!dictionary.contains(wordFromUser)) {
if (!illegalCharUsed && charsFromUser.isEmpty()) { // isEmpty check if users
// must use all letters
System.out.println("well done");
} else {
System.out.println("you didn't use the correct characters");
}
} else {
System.out.println("not a legal word");
}

Categories

Resources