This is a snippet of my code. I already fixed this bug, but I just don't understand why it works now. I'm not sure if I explained this correctly, so please ask any question if necessary. The bug is that the variable puncation changes to the correct value test when the statement is located in the place where I commented, the statement works. But, it does not work when the statement is located in the place where I commented, the statement does not work.
if (endOfSen) {
/////////////////The statement below works when it is here./////////////
/////////////////OUTPUT 1 - occurs when the statement is placed here.
String puncation = null ;
/////////////////////
int orgSize = words.size(); //remember size of stack
//only runs if stack is not empty
if (!words.empty()) {
while (words.size() > 0) { //until last word
String word = words.pop();
///The statement below does not work when it is here///////
//////OUTPUT 2- occurs when the statement is placed here.
//String puncation = null ;
//if last word of sentence
if (orgSize == words.size() + 1) {
word = word.substring(0, 1).toUpperCase() + word.substring(1);
puncation = "test"; // just a test value
word = word.replace(puncation, "");
//////////////////test to see if works
System.out.println("puncation: " + puncation);
}
//if first word of sentence
if (words.size() == 0) {
//////////////////test to see if works
System.out.println("puncation: " + puncation);
word = word.toLowerCase();
word = word + "" + puncation;
}
newSen.push(word);
}
}
endOfSen = false;
}
}
OUTPUT 1 (Second puncation changes from original value)
puncation: test
puncation: test
Output 2 (Second puncation does not change from original value)
puncation: test
puncation: null
If the variable is declared inside the loop, then each iteration of the loop will see a different variable. Besides, you even initialize it to null when there, so each iteration will start with a null value.
When declared to null outside the loop, the variable will retain the value from previous iteration(s) of the loop.
Since orgSize never changes in the loop, and words shrinks by one each iteration, the first if statement can only ever be true on the first iteration. Second if statement can only ever be true on the last iteration.
So if puncation is initialized to null inside the loop, the only time it can be not null in the second if statement would be if words originally had size 1.
Simple debugging could have shown you all this.
This is not as much a scoping issue as it's just that the variable is being reset in the loop. I made an example below that is more explicit about the value being reset.
if (endOfSen) {
/////////////////The statement below works when it is here./////////////
/////////////////OUTPUT 1 //////////////////
String puncation = null ;
/////////////////////
int orgSize = words.size(); //remember size of stack
//only runs if stack is not empty
if (!words.empty()) {
while (words.size() > 0) { //until last word
String word = words.pop();
///The statement below does not work when it is here///////
/////////////////OUTPUT 2 //////////////////
// Puncation is beign reset here, each iteration of the loop
puncation = null ;
//if last word of sentence
if (orgSize == words.size() + 1) {
word = word.substring(0, 1).toUpperCase() + word.substring(1);
puncation = "test"; // just a test value
word = word.replace(puncation, "");
//////////////////test to see if works
System.out.println("puncation: " + puncation);
}
//if first word of sentence
if (words.size() == 0) {
//////////////////test to see if works
System.out.println("puncation: " + puncation);
word = word.toLowerCase();
word = word + "" + puncation;
}
newSen.push(word);
}
}
endOfSen = false;
}
}
Related
Edited from my original post because I found a work around.
I'm trying to use a while loop to check if inputs exist. I have inputs that can vary in size, meaning I can have one input in a case or multiple in another. I'm using a while loop to execute many lines of code if the input(s) are present. The issue is that I know that I'll have at least one input in a case but in another case I may have 5,6,7, etc.
For example if I have:
input0="taco";
input1="water";
input2="sand";
With the example above in mind how do I iterate the condition of the while loop to make sure input0, input1, and input2 get executed?
In this example all of the commands within the while loop would be executed as long as input0,1,2 exist and are defined. My hope is that the integer q will scale with each input and the code within the while loop executes based on the current input.
When the loop reaches input3 I'd like it to exit the loop because that input does not exist.
I currently have the following:
int q=0;
String inputV =input(q);
while(inputV.contains("~")){ //first iteration takes "taco"
//This is where my long lines of code that need to be executed are
// I'm hoping that q will populate with 0,1,2 as the loop goes on and take "taco" "water" "sand" respectively
q++;
inputV=input(q);
//The next iteration will be input(1) = input1 which is "water"
}
New edit given the comment from Roger. The execution is having trouble getting through the if(f.equals(field)) statement. It passes through the for loop but can't process the if statement.
String input(int q) {
String field = "input" + q;
for (String f: global.variables) {
if (f.equals(field)) {
return (String) this.namespace.getVariable(field);
}
}
return null;
}
int q=0;
String inputV = input(q);
while(inputV != null) {
print(q + " " + inputV);
print("The input parameter is not null");
print("The input value is " + inputV);
// long lines of code executed within the while loop
q++;
inputV=input(q); }
You can find the defined variables in this.variables, global.variables or via the namespace.getVariableNames(). So with a helper method it is possible. In the example below I assumed they are defined in the global space.
input0="taco";
input1="water";
input2="sand";
String input(int q) {
String field = "input" + q;
for (String f: global.variables) {
if (f.equals(field)) {
return (String) this.namespace.getVariable(field);
}
}
return null;
}
int q=0;
String inputV = input(q);
while(inputV != null) {
System.out.println(q + " " + inputV);
q++;
inputV=input(q);
}
But, isn't there a better way for you to define the values such as array or list?
A class words defines a recursive function to perform string related operations. The class details
are given below:
Class name : words
Data members/instance variables
text : to store string.
w : integer variable to store total words.
Member functions/methods
words( ) : constructor to store blank to string and 0 to integer data.
void Accept( ) : to read a sentence in text. Note that the sentence may contain more
than one blank space between words.
int FindWords(int) : to count total number of words present in text using Recursive
Technique and store in ‘w’ and return.
void Result( ) : to display the original string. Print total number of words stored in
‘w’ by invoking the recursive function.
I tried this code
public static int CountWords(String str) {
int c = 0;
int i = str.indexOf(" ");
if (str.isEmpty()) {
return 0;
}else
if (i == str.indexOf(" ")) {
return c++;
}
//str.substring(0,str.indexOf(" ")-1);
c++;
return c + CountWords(str.substring(i + 1));
}
but i need to return an integer value and i am confused with that..
In your code, the last return statement is inaccessible. Reason: you have put an if-else block and have put return in both the cases. So the function actually gets returned from the if-else block itself (within else, the condition of if is always true since you assigned the very value i.e. str.indexOf(" ")).
I have written down the code according to the question you gave above...
public int findWords(int i){
if(i > text.lastIndexOf(" "))
return 1;
i = text.substring(i).indexOf(" ") + i;
if(i < 0)
return 1;
if(text.substring(i).equals(null))
return 0;
return( findWords(i+1) + 1);
}
Hope you find it well working.
Your function already is returning a integer, it just happens to always be 0.
This is due to
else if (i == str.indexOf(" ")) {
return c++;
}
Always being true and c++ only updating after the return statement was passed.
This happens because you already set i to be the indexOf(" ") and due to the implementation of incrementation using int++. Also, keep in mind hat you need to increase the number of words by 2 here, since you're ending the function between two words.
Therefore, use this instead:
else if (i == str.lastIndexOf(" ")) {
return c+2;
}
You should see that now the function is returning the correct amount of words.
Snippet of the code
while(!((input = sc.nextLine()) != null)) {
sc = new Scanner(input).useDelimiter(" ");
while (sc.hasNextLine()) {
in[index] = sc.next();
index++;
}
if (index < 3 || !in[0].equals("ping")) {
throw new IllegalArgumentException(
"Usage ping <destination> <port number missing> . . . ."
+ in[0] + " " + in[1] + " " + in[2]);
}
}
I want to keep reading user inputs but after the first iteration, i get no new line found. Scanner does not wait for the user input but rather advances on.
Thanks
Your top-level while loop is doing the opposite of what you want. First it sets input equal to sc.nextLine(), which is good. Then input is compared to null. If this comparison yields true, then you have input, which means that the loop should continue. However, you are then negating the result of that comparison, which makes the loop terminate when there is input.
Remove the exclamation point, and you should be good.
EDIT
On second thought, your inner while loop is exiting when sc.hasNextLine() returns false. After that, you will go through the conditional statement and return to the top. Since sc.hasNextLine() already returned false, of course sc.nextLine() will return null. The input has already ended in the inner loop, so the outer loop will exit as well.
I'm sure if you read the snippet you'll understand what I'm trying to do. However, I tried it first with null and "". I think .eoln() won't work because I'm asking for multiple lines of input, of which all have an end of line. I would preferably have the loop terminate when the user returns an empty line. For some more background, I've used the ==/!= and .equals() operators/method to experiment. I also just tried a do/while to no avail.
The asterisks were added to test if the empty string was an issue for the while statement.
Can anyone explain what I clearly don't understand about Java/TextIO yet?
EDIT - Revised Code Snippet:
while(write){
pl("Begin writing content to fill file.");
pl("");
pl("Return a line with a single SPACE or");
pl("\"\\n\" to represent line breaks in your");
pl("");
pl("Return two asterisks ** when done writing,");
pl("and you will be then prompted to select a file");
pl("to save your writing to.");
String input = TextIO.getln();;
String value = new String();
while(!(input.equals(""))) {
if (input == " " || input == "\\n") {
value += "\\n" + "\\n";
} else {
value += input + " ";
} // end if/else //
input = TextIO.getln();
} // end while(input) //
TextIO.writeUserSelectedFile();
p(value);
TextIO.writeStandardOutput();
pl("Would you like to write to another file?");
Boolean cont = TextIO.getBoolean();
write = cont;
}
}
So I am trying to read through a .txt file and find all instances of html tags, push opening tags to a stack, and then pop it when I find a closing tag. Right now I am getting String out of bounds exception for the following line:
if(scan.next().startsWith("</", 1))
{
toCompare = scan.next().substring(scan.next().indexOf('<'+2), scan.next().indexOf('>'));
tempString = htmlTag.pop();
if(!tempString.equals(toCompare))
{
isBalanced = false;
}
}
else if(scan.next().startsWith("<"))
{
tempString = scan.next().substring(scan.next().indexOf('<'+1), scan.next().indexOf('>'));
htmlTag.push(tempString);
}
It is telling me that the index of the last letter is -1. The problem I can think of is that all of the scan.next() calls are moving onto the next string. If this is the case, do I need to just write
toCompare = scan.next()
and then so my comparisons?
You have two major problems in your code:
you're calling scan.next() way too much and as you expect, this will move the scanner to the next token. Therefore, the last one will be lost and gone.
.indexOf('<'+2) doesn't return the index of '<' and adds 2 to that position, it will return the index of '>', because you're adding 2 to the int value of char < (60; > has 62). Your problem with index -1 ("It is telling me that the index of the last letter is -1.") comes from this call: .indexOf('<'+1) this looks for char '=' and if your string doesn't contain that, then it will return -1. A call for #substring(int, int) will fail if you pass -1 as the starting position.
I suggest the following two methods to extract the value between '<' and '>':
public String extract(final String str) {
if (str.startsWith("</")) {
return extract(str, 2);
} else if (str.startsWith("<")) {
return extract(str, 1);
}
return str;
}
private String extract(final String str, final int offset) {
return str.substring(str.indexOf('<') + offset, str.lastIndexOf('>'));
}
As you can see, the first method evaluates the correct offset for the second method to cut off either "offset. Mind that I wrote str.indexOf('<') + offset which behaves differently, than your str.indexOf('<' + offset).
To fix your first problem, store the result of scan.next() and replace all occurrences with that temporary string:
final String token = scan.next();
if (token.startsWith("</")) { // removed the second argument
final String currentTag = extract(token); // renamed variable
final String lastTag = htmlTag.pop(); // introduced a new temporary variable
if (!lastTag.equals(currentTag)) {
isBalanced = false;
}
}
else if (token.startsWith("<")) {
htmlTag.push(extract(token)); // no need for a variable here
}
I guess this should help you to fix your problems. You can also improve that code a little bit more, for example try to avoid calling #startsWith("</") and #startsWith("<") twice.