I have a basic method which returns a string based on the input of a user:
public String getString() {
String message = inputGenerator.getMessage(); // Returns user inputted string
String messageStart = message.substring(0, 3); // Get start of message
String concat = ""; // Variable to concatenate messages
if(messageStart.equals("Hi")) {
concat += message; // Append input to concat string.
inputGenerator.getMessage(); // Call for another user prompt
} else {
concat += message; // Append input to concat string.
}
return concat; // Return concatenated string.
}
What I want to do:
As you can hopefully work out, what I want to do is prompt a user for more messages if the start of the message includes the word hi, until it doesn't, and return that concatenated string, e.g.
>> Enter a string ("hiexample")
>> Enter a string ("hianotherexample")
>> Enter a string ("nothi")
>> returns "hiexamplehianotherexamplenothi"
The problem
The problem is that the if statement only works once because inputGenerator.getMessage(); obviously jumps out of the conditional after being called.
If I try to use a while() statement instead, it runs forever and eventually crashes the program.
This seems shorter and more elegant:
public String getString() {
StringBuilder msg = new StringBuilder();
String read;
do {
read = inputGenerator.getMessage();
msg.append(read);
} while (read.toLowerCase().startsWith("hi"));
return msg.toString();
}
I use the StringBuilder because it's more efficient than String concatenation like you do.
Let me explain:
concat += message;
gets inflated by the compiler to
concat = new StringBuilder(concat).append(message).toString();
Now guess which is more efficient. :)
Is this what you're thinking?
public String getString()
{
String result = "";
while (true)
{
String message = inputGenerator.getMessage();
result += message;
if (!message.startsWith("hi"))
{
break;
}
}
return result;
}
I think you want 2 as the second argument to substring since your continuation string is "hi", right?
EDITS: Several tweaks thanks to Floegipoky, clcto and StackOverflowException (see comments/other answers below).
Related
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.
I have an assignment where I'm supposed to have a method that formats an array of String objects to be tabulated a certain way with a header, and put all the objects (after being formatted) nicely into a single String for the method to return. This method is inside an object class, so it ultimately will be formatting multiple objects the same way, so I need it to format the same way with various String lengths.
Here's what I need the output to look like:
Hashtags:
#firstHashtag
#secondHashtag
Each hashtag is in a String[] of hashtags,
i.e.
String[] hashtags = ["#firstHashtag", "#secondHashtag"]
So basically I need to use string.format() to create on single string containing a tabbed "Hashtags:" header, and then each String in the "hashtags" array to be on a new line, and double-tabbed. The size of the "hashtag" array changes since it is in an object class.
Could someone help me use String.formatter?
This is what my method looks like so far:
public String getHashtags()
{
String returnString = "Hashtags:";
String add;
int count = 0;
while(count < hashtags.length)
{
//hashtags is an array of String objects with an unknown size
returnString += "\n";
add = String.format("%-25s", hashtags[count]);
//here I'm trying to use .format, but it doesn't tabulate, and I
//don't understand how to make it tabulate!!
count++;
returnString = returnString + add;
}
if(hashtags == null)
{
returnString = null;
}
return returnString;
}
Any helpful advice on what to do here with formatting would be greatly appreciated!!!
If you are trying to use real tabs and not spaces, then just change your program to be like this one:
public String getHashtags()
{
if(hashtags == null)
{
return null;
}
String returnString = "Hashtags:";
int count = 0;
while(count < hashtags.length)
{
//hashtags is an array of String objects with an unknown size
returnString = returnString + "\n\t\t"+hashtags[count];
count++;
}
return returnString;
}
Your String.format() statement will create a String that is left-justified and padded to 25 spaces. For example, this line:
System.out.println("left-justified >" + String.format("%-25s", "hello") + "<");
outputs:
left-justified >hello <
The other thing is that you're not really using tabs (I don't see the tab character in your program). String.format() is creating Strings that are length 25 and left-justified. Keep that in mind as you create the return string. Also, your loop as adding a newline character each time. That's why you're getting multi-line output.
As an exercise, the code block below intends to recursively go through a string and remove all the of the "x" characters. It does that, but I would like to keep track of the newStr without passing it as a parameter in the method. Is there anyway to move it into the method body?
Thanks!
public static String deathToX(String str, String newStr) {
//look for x char
if(str.substring(0, 1).equals("x")) {
//do nothing
} else {
//add non-x char to newStr
newStr += str.charAt(0);
}
if(str.length() == 1) {
return newStr;
}
return deathToX(str.substring(1), newStr);
}
public static void main(String[] args) {
System.out.println("Return: " + deathToX("xnoxmore", ""));
}
Well, you could change the code to:
public static String deathToX(String str)
{
// Termination case
if (str.length() == 0)
{
return str;
}
// Work out whether or not we want the first character
String prefix = str.startsWith("x") ? "" : str.substring(0, 1);
// Let the recursive call handle the rest of the string, and return
// the prefix (empty string or the first character) followed by the
// x-stripped remainder.
return prefix + deathToX(str.substring(1));
}
Is that the sort of thing you were thinking of?
Of course, this is a horribly inefficient way of doing string manipulation, but I assume you're more interested in the recursive nature of things.
I would like to keep track of the newStr without passing it as a parameter in the method.
Why? Passing the intermediary result into the function is often required in functional-style recursive programming. What I do is make a function that handles the bulk of the work and accepts the accumulator, and make a wrapper function that calls the previous one with the required starter value:
private static String deathToX0(String str, String newStr) {
// the original implementation
}
public static String deathToX(String str) {
return deathToX(str, "");
}
As an aside, you might not want to use a String for the intermediate result because of the copying involved. A StringBuilder would be faster.
The short answer is yes... with recursion typically on the way down the tree you work out the bit at each level in this case blank or the current character. So the return statement should call itself recursively then at the bottom of the tree the answer you wanted is reconstructed by adding together the sections at each level.
public static String deathToX(String str){
if (!str.isEmpty()){
return (str.substring(0, 1).equals("x") ? "" : str.substring(0, 1)) + deathToX(str.substring(1));
}else{
return "";
}
}
public static void main(String[] args){
System.out.println("Return: " + deathToX("xnoxmore"));
}
In the sample above I used the shorthand if format to put it all on one line but you could expand it out. You should be able to see that the recursive function recurses on the return statement and I put in a special case for the last level. If you were to split it and put this levels answer in a local variable e.g. tmp then you would use:
return tmp + deathToX(str.substring(1));
Remember recursion means that the current execution is only paused until the lower ones finish so you can happily store info to recover on your way back up. Hope this helps :)
public class solution {
// Return the changed string
public static String removeX(String input){
if(input.equals("") || input.equals("x"))
return "";
String returnStr="";
removeX(input.substring(1));
for(int i=0;i<input.length();i++)
{
if(input.charAt(i)=='x')
continue;
else
returnStr+=input.charAt(i);
}
return returnStr;
}
}
This is my approach. This code goes to the end of the string, if it gets X as last string, it returns ""(nothing), then it checks the whole substring for "x", if its present in the string, it will continue, else it will append rest character to that string and it goes on.
Finally returns the updated string.!
Hope this helps..!! well, this is my first contribution here :)
I am trying to make a recursive class that takes a string as a parameter and returns a line from a stringlist that starts with the parameter string. If it cant find a match, it should return "". I seem to be almost there but for some reason once the string is found and enters the if statement, it returns the string, but then jumps to the other statement in the code. In other words, its not returning it for some reason. any help would really help.
public String getLineStartingWith(String _string){
System.out.println("GETLINESTRING: " + _string);
//place parameter string into local string
String string = _string;
//return the line from the stringlist if it starts with the
//parameter string
if(currentString.startsWith(_string)){
System.out.println("CURRENT STRING: " + currentString);
return currentString;
}
restOfList.getLineStartingWith(_string);
return "";
//return restOfList.getLineStartingWith(_string);
}
EDIT
I made some changes to my code. But for some reason, after it returns the current string, it returns restOfList.getLineStartingWith(string) everytime. I think its not detecting if its empty or not
public String getLineStartingWith(String string){
System.out.println("GETLINESTRING: " + string);
//return the line from the stringlist if it starts with the
//parameter string
if(currentString.startsWith(string)){
System.out.println("CURRENT STRING: " + currentString);
return currentString;
}
if(restOfList.isEmpty){
return "";
}
return restOfList.getLineStartingWith(string);
}
Why are you doing this?
//place parameter string into local string
String string = _string;
This code has exactly the same effect:
public String getLineStartingWith(String string){
System.out.println("GETLINESTRING: " + string);
// etc.
String are immutable, so you can't do anything bad to the input. Also, you're not even using string (all of your later code uses _string).
I think your problem is that this isn't being returned:
restOfList.getLineStartingWith(_string);
Try:
return restOfList.getLineStartingWith(_string);
You probably also need another base-case that handles restOfList being empty.
I'm sorry if this might not answer your question.
It seems to me that you just want to display all the lines that start with that particular String. How about a simple loop on each item in the String list? How about something like this:
for (String line : allLines) {
if (line.startsWith(string)){
System.out.println(line);
}
}
Sorry if this is not what you want.
whats wrong with my code, i want it so if the string you input is 33*10= it outputs the correct answer, but it outputs 0.0 in this case and if the string was 33+10 it would output 44
while (character != '=')
{
for (int i = 0; i < calc.length(); i++)
{
character = calc.charAt(i);
try
{
final String characterString = Character.toString(character);
characterString = characterString +characterString
setOperand(Double.parseDouble(characterString));
if (flag == 0)
{
operand1 = (Double.parseDouble(characterString));
result = operand1;
flag = 1;
}
getResult();
}
}
catch (Exception e)
{
try
{
operator = character;
}
catch (Exception e2)
{
System.out.println("Enter a number");
}
}
}
}
You cannot add char to your String, use StringBuffer:
StringBuffer buffer = new StringBuffer();
buffer.add("3+3=");
buffer.add("6");
System.out.println(buffer.toString());
String mainString="i am ready to add characters";
char c='v';
String toAdd=Character.toString(c);
mainString = mainString.concat(toAdd);
Instead of having character = calc.charAt(i); which is only grabbing 1 character try...
StringBuilder sb = new StringBuilder();
while(calc.charAt(i).isDigit()){
sb.append(calc.charAt(i));
i++;
}
...
final String characterString = sb.toString();
Doing this will attach all consecutive digits to the string builder and then turn that into a string to be parsed.
This may work, but your code has a lot of places that it could fail. For instance, you're using exceptions as a decision method, which is typically frowned upon.
Objects of type String can't be changed after their creation. You have either to build a new String out of the old String an the one you want to append or - way better - use a StringBuilder. If you need synchronization for the String manupilation you would use a StringBuffer instead a StringBuilder. Both are essantially the same but the latter one is threadsafe whereas the first one is not.
final String characterString = Character.toString(character);
characterString = characterString +characterString
I don' really get what you want to do here. Yes you could use the second line, but there is a problem:
characterString +characterString
will create a new object, thus charactrerString will be assigned a new object. This are you preventing by the final statement in the first line.
Moreover characterString +characterString would create a String composed by a String repeated 2 times. Like
characterString = "123456";
characterString = characterString + characterString;
System.out.print(characterString);
Would print 123456123456 in the console. And don't know if this is your intention.
And you are initializing the String characterString inside the loop. So each pass you are creating a new one, discarding the old one. Unnecessary object creation an destruction should be avoided if possible.