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.
Related
My program reads a custom generated string which follows this pattern:
#INT{0,1,2}/STRING/LONG#INT{0,1,2}/STRING/LONG#.......#
So that's a hash at the start and end of the string, and seperating each substring, with each substring containing an int from 0-2, a string name, and a long value (taken from system clock). These subvalues are seperated by forward slashes.
My program successfully splits the main string on the hashes in the function 'splitOnHash', and assigns these to an array list of strings, which I can print out, and this seems to work nicely.
Next, in the second function, I iterate through this new arraylist, I want to split each substring on the '/' character, and stick each value into a custom 'HesitationEvent' object. Here is my code:
package sg;
import java.util.ArrayList;
import java.util.List;
import sg.events.HesitationEvent;
public class HesitationDataReader {
private static List<String> substrings = new ArrayList<String>();
private static List<HesitationEvent> events = new ArrayList<HesitationEvent>();
private static void splitOnHash(String HesData) {
for (String ret : HesData.split("#")) {
if (ret!= "") substrings.add(ret);
}
}
private static void createEventObjects() {
int code;
String object;
long time;
int c = 1;
for (String sub : substrings) {
System.out.println("count " + c);
c++;
String[] comp = sub.split("/");
System.out.println("comp:"+comp+":comp");
code = Integer.parseInt(comp[0]);
object = comp[1];
time = Long.parseLong(comp[2]);
HesitationEvent hes = new HesitationEvent(code, object, time);
events.add(hes);
}
}
public static void main (String args[]) {
String ourString = "#0/diamonds4/1392748304285#2/diamonds4/1392748304333#0/hearts7/1392748304364#2/hearts7/1392748305035#" +
"1/deck/1392748305456#1/deck/1392748311696#1/deck/1392748313489#1/deck/1392748315490#0/clubs7/1392748317599#" +
"2/clubs7/1392748317623#0/clubs5/1392748317623#2/clubs5/1392748317647#0/spades3/1392748317647#2/spades3/1392748323913#" +
"1/spades3/1392748324616#2/spades3/1392748324710#0/diamonds4/1392748324710#2/diamonds4/1392748324734#0/clubs5/1392748324782#" +
"2/clubs5/1392748325126#2/clubs5/1392748325214#1/clubs5/1392748325625#2/clubs5/1392748325782#0/spades6/1392748325806#" +
"2/spades6/1392748325918#0/spades3/1392748326006#2/spades3/1392748326262#0/diamonds4/1392748326262#2/diamonds4/1392748326678#" +
"2/diamonds4/1392748326830#1/diamonds4/1392748327498#2/diamonds4/1392748328094#0/spades6/1392748328118#2/spades6/1392748328206#" +
"0/diamonds13/1392748328238#2/diamonds13/1392748328534#0/diamonds13/1392748328790#2/diamonds13/1392748329046#0/hearts7/1392748329582#" +
"2/hearts7/1392748329942#0/hearts7/1392748330150#2/hearts7/1392748330246#0/hearts7/1392748330454#2/hearts7/1392748330654#" +
"1/deck/1392748333057#0/spades10/1392748333990#2/spades10/1392748334006#0/clubs13/1392748334006#2/clubs13/1392748334038#" +
"0/hearts1/1392748334038#2/hearts1/1392748334477#1/hearts1/1392748334927#2/hearts1/1392748335093#0/diamonds13/1392748335261#" +
"2/diamonds13/1392748335325#0/hearts7/1392748335341#2/hearts7/1392748335797#2/hearts7/1392748336013#2/hearts7/1392748336237#" +
"2/hearts7/1392748336325#2/hearts7/1392748336429#1/hearts7/1392748337240#2/hearts7/1392748337517#0/clubs4/1392748337525#" +
"2/clubs4/1392748337557#0/diamonds4/1392748337565#2/diamonds4/1392748337573#0/clubs5/1392748337573#2/clubs5/1392748337581#" +
"0/hearts6/1392748337581#2/hearts6/1392748337589#0/spades6/1392748337589#2/spades6/1392748337613#0/diamonds13/1392748337629#" +
"2/diamonds13/1392748337637#0/spades10/1392748337653#2/spades10/1392748337661#0/spades10/1392748337933#2/spades10/1392748337965#" +
"0/clubs13/1392748337965#2/clubs13/1392748338509#2/clubs13/1392748338557#1/clubs13/1392748338919#2/clubs13/1392748339237#" +
"1/deck/1392748341879#0/clubs13/1392748342477#2/clubs13/1392748342549#0/spades6/1392748345549#2/spades6/1392748345581#" +
"0/hearts1/1392748345637#2/hearts1/1392748345837#0/hearts1/1392748346421#2/hearts1/1392748346661#0/hearts9/1392748350302#" +
"2/hearts9/1392748350381#0/spades11/1392748350381#2/spades11/1392748350381#0/hearts2/1392748350381#2/hearts2/1392748350397#";
splitOnHash(ourString);
//for (String s:substrings) {
// System.out.println(s);
//}
createEventObjects();
}
}
Please ignore the variable c, and the for loop at the bottom, I used c to determine at what point the for loop crashes (the very first iteration). The for loop at the bottom (commented out) was used to confirm my splitOnHash function returned what I expected (it seems to work fine).
So essentially I am trying to split each substring into an array, and then pull and convert each value to the right type. I've also tried with split("/",3) to return exactly 3 values, but it gets the same result, which is:
count 1
Exception in thread "main" comp:[Ljava.lang.String;#1fae3c6:comp
java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at sg.HesitationDataReader.createEventObjects(HesitationDataReader.java:30)
at sg.HesitationDataReader.main(HesitationDataReader.java:87)
It's hard to tell here, but the "comp:[Ljava.lang.String;#1fae3c6:comp" is actually output of the program which appears in the midst of the exception for some reason. This is from the line where I try to print out the value of comp, surrounded by comp:VALUE:comp (I did this in case it prints an empty or null string, so I can see there is no gap between the colons.
So for some reason, in the first iteration, the output of sub.split into the String[] comp produces "Ljava.lang.String;#1fae3c6", when I'm expecting it to come up with something more like this: "0 diamonds4 1392748304285".
I just changed the code to try and access a location in the array rather than printing all 3 segments, and I get this error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
at sg.HesitationDataReader.createEventObjects(HesitationDataReader.java:29)
at sg.HesitationDataReader.main(HesitationDataReader.java:89)
There is obviously something wrong here, but I can't see the problem! I cannot use the original method I used to split the hashes, because I'm not returning strings in any order this time, I want to access specific values and convert them to specific types.
Thanks in advance for any help!
Here is the problem:
(ret!= "")
Should be:
if (!ret.equals(""))
I believe the error is causing insertion of empty strings.
So I have a String Array (sConsonantArray) and have all of the consonants stored in it.
String[] sConsonantArray = new String[] {"q","w","r","t","p","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m"};
I need to check if the second last value of a word (sWord) equals a value in the array and I don't know how to call each value in the array to compare the letters other than doing sConsonantArray[5] (checking them each one at a time). I am looking for an easier way to call them, thanks for your help. Also, it doesn't appear that the (&&) operator will work, other suggestions would be appreciated.
else if (sWord.substring(sWord.length()-2,sWord.length()-1).equals(sConsonantArray I DONT KNOW WHAT TO PUT HERE)) && (sWord.substring(sWord.length()-1,sWord.length()).equalsIgnoreCase("o"))
{
System.out.println("The plural of " + sWord + " is " + (sWord + "es"));
}
It seems to me that it would be simpler to have the consonants as a string and then use charAt:
private static final String CONSONANTS = "bcdfgh...z";
if (CONSONANTS.indexOf(word.charAt(word.length() - 2)) {
...
}
If you really want to use an array, you could change your array to be in order and then call Arrays.binarySearch. Another alternative would be to create a HashSet<String> of the consonants and use contains on that.
Try something like
else if (Arrays.asList(sConsonantArray).contains(
sWord.substring(sWord.length()-2,sWord.length()-1))
&& (sWord.substring(sWord.length()-1,sWord.length()).equalsIgnoreCase("o"))) {
// do something
}
or Write a small Util method
public static boolean isInConstants(String yourString){
String[] sConsonantArray = new String[] {"q","w...}
for (String item : sConsonantArray) {
if (yourString.equalsIgnoreCase(item)) {
return true;
}
}
return false;
}
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).
Say I have a string,
String templatePhrase = "I have a string that needs changing";
I also have a method to replace words in any given String. Here is the method:
public String replace(String templatePhrase, String token, String wordToPut) {
return templatePhrase.replace(token, wordToPut);
}
Now say (for the sake of my actual task) I have all the words in my String str in a List named wordsInHashtags. I want to loop through all the words in wordsInHashtags and replace them with words from another List named replacement using the replace() method. Each time the loop iterates, the modified String should be saved so it will hold its replacement(s) for the next loop.
I will post my code if anyone would like to see it, but I think it would confuse more than help, and all I am interested in is a way to save the modified String for use in the next iteration of the loop.
I was just reading about strings in beginning Java 2 the other day, :"Strings Objects are immutable" Cant be changes basically however StringBuffer Objects were created to deal with such a circumstance as i understand it. You could try:
StringBuffer templatePhrase = "I have a string to be changed";
templatePhrase.replace(token, wordToPut);
String replacedString = (String)templatePhrase;
Line 3 may cause a problem?
public class Rephrase {
public static void main(String[] args) {
/***
Here is some code that might help to change word in string. originally this is a Question from Absolute Java 5th edition. It will change two variable whatever you want but algorithm never change.So the input from keyboard or any other input source.
********/
String sentence = "I hate you";
String replaceWord = " hate";
String replacementWord = "love";
int hateIndex = sentence.indexOf(replaceWord);
String fixed = sentence.substring(0,hateIndex)+" "+replacementWord+sentence.substring(hateIndex+replaceWord.length());
System.out.println(fixed);
}
}
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 :)