Storing StringBuffer - java

I have a StringBuffer in my Class which deletes certain characters if the conditions are met in the IF statement and prints the statement. However, this could be repeated many times. If the second condition is met, the first statement will print out WITHOUT the characters being deleted.
Is there a way around this? Below is my code.
if (status == 1 && item == item1[1]){
item1[1] = "*";
w = sb1.append(item1[1]+"["+item2[1]+"] ");
sb1.delete(1,4);
}else if (status == 1 && item == item1[2]){
item1[2] = "*";
x = sb1.append(item1[2]+"["+item2[2]+"] ");
sb1.delete(1,4);
}else if(status == 1 && item == item1[3]){
item1[3] = "*";
y = sb1.append(item1[3]+"["+item2[3]+"] ");
sb1.delete(1,4);
}
return w.toString()+x.toString()+y.toString()+z.toString();
What i'm trying to achieve is the following:
I have a toString which is made up of:
item1[1]+"["item2[1]"] "+item1[2]+" ["+tem2[2]+"]"
I want to do this:
if item1 is marked as taken, it will be changed to "*" and remove the item2[1] and the [ ] around it and then return it as:
eg: item1[2] = x
item2[2] = 1
* x[1]
( * used to be item1[1] )
but if the loops passes through again, my current class does this:
*[] *[1]
i want it to be:
* *
When the loop is complete

A general problem: item looks like a String, item[] like a String[]. Do not use == with Strings, it will produce unexpected result occasionally. Use equals() instead:
if (status == 1 && item.equals(item1[1])) {
Use this pattern for the other conditional checks too.
(and add a test/handler for item == null which now would be necessary)
Another improvement: replace StringBuffer with StringBuilder and don't concatenate Strings while passing them to append. Not to correct an error, but to give better performance:
w = sb1.append(item1[1]).append("[").append(item2[1]).append("] ");

Your code looks suspicious. Lets pull out the 3-times test whether 'status == 1' (is there a hidden boolean in the variable, which tries to come out?). And put some fresh air between the tokens, to make the job for the eye more easy to split them:
if (status == 1)
{
if (item.equals (item1[1]))
{
item1[1] = "*";
w = sb1.append (item1[1] + "[" + item2[1] + "] ");
sb1.delete (1, 4);
}
else if (item.equals (item1[2]))
{
item1[2] = "*";
x = sb1.append (item1[2] + "[" + item2[2] + "] ");
sb1.delete (1, 4);
}
else if (item.equals (item1[3]))
{
item1[3] = "*";
y = sb1.append (item1[3] + "[" + item2[3] + "] ");
sb1.delete (1, 4);
}
}
return (w.append (x). append (y). append (z)).toString ();
//
Looks like 3times the same statement, just iterating through 1,2,3 and w,x,y. I used append in the last line too, and just put the 'toString ()' on the end result.
Let's make a loop from the 3 statements:
if (status == 1)
{
for (int i = 1; i < 4; ++i)
{
if (item.equals (item1[i]))
{
item1[i] = "*";
w = sb1.append (item1[i] + "[" + item2[i] + "] ");
sb1.delete (1, 4);
}
}
}
return (w.append (w). append (w). append (w)).toString ();
Depending on your code, sideeffects, threads and so on, this might result in something different, but I don't think so. Especially I don't know what w,x,y are by default, if not assigned in that code part. And the code looks, as if item is either equals item1[1] or item1[2] or item1[3] exclusively. But it might be equal to all 3, and then the loop will hit 3 times instead of 1 time.
However, item1/item2 is a code smell. It smells like 2-dim-array or not well thought of object orientation (item.color, item.name or something like that).

Related

How to Recursively Parse Substrings Inside of Parentheses

I'm writing a LISP interpreter, in Java, and I'm trying to create a function that can recursively and dynamically evaluate all of the arguments inside of a set of parentheses into a single value. It needs to solve any combination of input parameters needing to be evaluated. For example, + 2 3 means no parameters need to be solved, + (+ 1 2) (+ 1 2) means both parameters need to be solved, + 1 (+ 1 2) means only the second parameter needs to be solved, and + (+ 1 2) 1 means only the first parameter needs to be solved. In this, I'm assuming that all of the operations that can be performed will only have 2 parameters (+, -, *, /, etc)
I have included my snippet of what already works. My function can solve down the input if either both parameters need to be solved, or if neither of them need to be solved. My issue is that I can't figure out a way how to check if only one parameter needs to be solved. Note: I'm returning the results as strings on purpose.
public String test(String input) { //input comes in without outter-most parentheses
String param1, param2;
if (input.indexOf('(') != -1) { //'(' exists somewhere in the string
int param1Start = input.indexOf('(');
int iter = param1Start + 1;
int c = 1;
while (c != 0) { //loop through the string until the matching close parentheses is found
if (input.charAt(iter) == '(')
c++;
if (input.charAt(iter) == ')')
c--;
iter++;
}
String subs1 = input.substring(param1Start + 1, iter - 1);
param1 = test(subs1); //further evaluate the first parameter
int param2Start = iter + 1;
iter = param2Start + 1;
c = 1;
while (c != 0) { //loop through the string until the matching close parentheses is found
if (input.charAt(iter) == '(')
c++;
if (input.charAt(iter) == ')')
c--;
iter++;
}
String subs2 = input.substring(param2Start + 1, iter - 1);
param2 = test(subs2); //further evaluate the second parameter
} else { //no parentheses left in string, solving time
String[] splitter = input.split(" ", 3);
return Integer.toString(Integer.parseInt(splitter[1]) + Integer.parseInt(splitter[2]));
}
return Integer.toString(Integer.parseInt(param1) + Integer.parseInt(param2));
}
Can anyone find a way to check if only one parameter needs to be evaluated? Or post a better Java solution?

Print statements inside for loop causing several outputs instead of one, how can I fix this without using "return"?

I am a beginner coder. My code needs to display "yes" if the string input consists of 'l' + 'any character' + 'l'. For example, "uwbıclsl" should have a "yes" output because a letter is sandwiched between two l's. However, since my print statements are inside of my for loop, it displays several "yes" and "no" s. How can I fix it so that I only have 1 output(yes or no) and still have print statements instead of returns?
for (int i = 0; i < s.length(); i++) {
if ((s.charAt(i) == 'l') && (s.charAt(i + 2) == 'l')) {
System.out.print("YES");
} else
System.out.print("NO");
Better use regexes for this
System.out.println(s.matches(".*l.l.*") ? "YES" : "NO");
Do the below changes -
String result = "NO";
for (int i = 0; i < s.length(); i++) {
if ((s.charAt(i) == 'l') && (s.charAt(i + 2) == 'l')) {
result = "YES";
}
}
System.out.println(result);
Note - You dont need else block now, also you need to handle StringIndexOutOfBoundsException exception in your if statement, hope you can resolve this.
If you need to print Yes/No just once, try the below. Even if multiple matches, it just says Yes once. Also fixed "for" loop end length to (length()-2) to avoid Exception. Comment if you have any questions or this is not an expected solution.
boolean isFound = false;
for (int i = 0; i < s.length()-2; i++) {
if ((s.charAt(i) == 'l') && (s.charAt(i + 2) == 'l')) {
isFound = true;
}
}
System.out.println (isFound?"YES":"NO");
You also can drop the cycle and use regex
String s = "uwbıclsl".matches(".*(l.l).*") ? "yes" : "no";
System.out.println("s = " + s);
How about slightly modifying your current code to be in a separate method and subsequently returning "Yes" if you have found two l's separated by another char, since you do not need to carry on checking the rest of the string:
class Main {
public static void main(String[] args) {
String str = "uwbıclsl";
System.out.println(charBetweenTwoLs(str));
String str2 = "abclol";
System.out.println(charBetweenTwoLs(str2));
}
static String charBetweenTwoLs(String str) {
for (int i = 0; i < str.length() - 2; i++) { // Note the - 2 since you are checking on each iteration 2 characters ahead.
if (str.charAt(i) == 'l' && str.charAt(i+2) == 'l') {
return "Yes";
}
}
return "No"; // return No if two 'l' characters were not found sperated by another character.
}
}
Output:
Yes
Yes

If statement help on when to use commas and spaces

Basically I've built up a string and I need to put an if statement on when to use a comma and a space. So basically I need it be after the first element and not on the last element.
This is what my current code is:
And the output it returns is
"thing1thing2thing3"
I want to make the output to be
"thing1, thing2, thing3"
And I need an if statement as part of the requirements on when to place the commas and spaces.
Thanks in advance.
This might be a little advanced for you, but it's very easy when using Java 8 (if things is a Collection:
return Optional.of(things.stream()
.filter(thing -> thing.getCategory() == things.STUFF)
.collect(Collectors.joining(", ")))
.orElse("nothing");
If you're using Java 7, then you can do it manually:
StringBuilder sb = new StringBuilder();
for (Thing thing : things) {
if (things.getCategory() == some.STUFF){
sb.append(thing.getName()).append(", ");
}
}
if (s.isEmpty()) {
return "nothing";
}
return sb.delete(sb.length() - 2, sb.length()).toString();
I'd use a for-loop rather than a for-each loop - only because I see it as eliminating the need for an additional counter variable. This is how I'd approach the problem.
String[] things = {"thing 1", "thing 2", "thing 3", "thing 4"};
for(int i = 0; i < things.length; i++)
{
if(i < things.length - 1)
{
System.out.print(things[i] + ", ");
}
else
{
System.out.print(things[i] + ".");
}
}
There are a few unclear things about the question, so the code below is based on what I have understood so far.
String s = "";
boolean isComma = true; // true = comma, false = space.
for (Thing thing : things)
{
if (things.getCategory() == thing.STUFF)
{
//Check if there already exists an entry within the String.
if (s.length() > 0)
{
//Add comma or space as required based on the isComma boolean.
if (isComma)
{
s += ", ";
}
else
{
s += " ";
}
}
s += thing.getName();
}
}
if (s.equals(""))
{
s += "nothing";
}
return s;

Performance (JAVA) ~ String concatenation in a loop with prepending and appending

I'm having performance issues. Does anyone have a faster/better solution for doing the following:
String main = "";
for (String proposition : propositions) {
if (main.length() == 0) {
main = proposition;
} else {
main = "|(" + proposition + "," + main + ")";
}
}
I know concat and stringbuilder are faster, but i don't see how i can use these methods. Because of the following line of code:
main = "|(" + proposition + "," + main + ")";
Thanks in advance!
So from what I can tell there are 3 problems here:
Values are primarily prepended to the string.
For each value a character is appended.
If only one value is present, nothing should be appended or prepended.
With 2 or more items, the 0th item is handled differently:
0:""
1:"A"
2:"|(B,A)"
3:"|(C,|(B,A))"
It can be made quicker by making a few changes:
Reverse the algorithm, this means the majority of the work involves appending, allowing you to use StringBuilders.
Count the number of closing )'s and append those after the loop is finished.
Special case for 0 or 1 items in the list.
With those changes the algorithm should be able to use a StringBuilder and be a lot quicker.
Attempt at an algorithm:
int length = propositions.size();
if (length == 0) {
main = "";
} else {
StringBuilder sb = new StringBuilder();
int nestingDepth = 0;
// Reverse loop, ignoring 0th element due to special case
for (int i = length - 1; i > 0; i--) {
sb.append("|(").append(propositions.get(i)).append(',');
nestingDepth++;
}
// Append last element due to special casing
sb.append(propositions.get(0));
for (int i = 0; i < nestingDepth; i++) {
sb.append(')');
}
main = sb.toString();
}
I believe this should produce the correct results, but it should give the right idea.
The problem is that you're prepending and appending to the string as you go. String and StringBuilder dont handle this well (and give quadratic performance). But you can use a dequeue which supports insertion at start and end to store all the pieces. Then finally you can join the bits in the dequeue.
ArrayDeque bits = new ArrayDeque();
for (String proposition : propositions) {
if (bits.size() == 0) {
bits.push(proposition);
} else {
// Add prefix
main.offerFirst("|(" + proposition + "," );
// Add suffix
main.push(")");
}
}
StringBuilder sb = new StringBuilder();
for( String s : bits) {
sb.append(s);
}
main = sb.toString();
Assuming this is an array of propositions, you could first sum the length of the String(s) in the array. Add 4 for your additional characters, and subtract 4 because you don't use those separators on the first element. That should be the perfect size for your output (this is optional, because StringBuilder is dynamically sized). Next, construct a StringBuilder. Add the first element. All subsequent elements follow the same pattern, so the loop is simplified with a traditional for. Something like,
int len = Stream.of(propositions).mapToInt(s -> s.length() + 4).sum() - 4;
StringBuilder sb = new StringBuilder(len); // <-- len is optional
sb.append(propositions[0]);
for (int i = 1; i < propositions.length; i++) {
sb.insert(0, ",").insert(0, propositions[i]).insert(0, "|(").append(")");
}
System.out.println(sb);

Check if letter x is between two quotes

I'd like to check if some character is between 2 other chars.
For example, given the following String:
String myString = "Hello, my name is 'Tesda', and this is 'ASDfs'."
I want to check if the 'S' in "ASDfs" is between '' or not, also keeping in mind I want to check every '', not jump directly to the second ''.
I've tried a silly code (I'm not familiar with this at all, as I didn't need it until now), which is:
boolean isBetween;
if (!MyString.substring(MyString.indexOf("'"), MyString.indexOf("'")).contains("S"))
isBetween = true;
Well, this didn't work and I don't understand how to make it perfectly.
Also, I want to replace that S with another letter, but I want only between the '', not the one after "my name is", I thought about getting the index of the letter, if it's inside '', then replace that letter in that specific index, is that possible?
Using the provided answer, I've made the following code ( which why i posted this question for ) :
String NewText = "Hello, My NAme is 'Ba', i'm from 'LA' ";
boolean contains = false;
int indexOfS = -1;
String MyString_temp = NewText;
while (MyString_temp.length() >= 0) {
int first = MyString_temp.indexOf("\'");
if(first == -1)
{
break;
}
int second = MyString_temp.substring((first + 1)).indexOf("\'");
second = second + first + 1;
if(second == -1)
{
break;
}
contains = MyString_temp.substring(first,second).contains("A");
if (contains) {
break;
}
MyString_temp = MyString_temp.substring((second + 1));
}
Log.i("ResultTest","Index is: " + indexOfS + " - Text is: " + MyString_temp);
if(!contains){
Log.i("ResultTest", "Yes " + i);
Log.i("ResultTest","TeF: " +NewText.replace(NewText.substring(indexOfS,indexOfS+1),"Test"));
} else
Log.i("ResultTest", "No " + i);
Output
Index is: -1 - the text here ..
Failed to output, invalid index
Consider using regular expressions. Your example could be as simple as
MyString.matches("\'S\'");
EDIT: Updated answer for updated question: Your initial code block looked like it might have done the trick, however you must remember that indexOf() only returns the first occurence of what you need. This could work:
String MyString_temp = MyString;
String lookingFor = "S";
String separator = "\'";
boolean contains = false;
int indexOfLooking = -1;
while (MyString_temp.length() >= 0) {
int first = MyString_temp.indexOf(separator);
if(first == -1) {
break;
}
int second = MyString_temp.substring(first + 1).indexOf(separator);
second += first + 1;
if(second == -1) {
break;
}
indexOfLooking = MyString_temp.substring(first, second).indexOf(lookingFor);
contains = (indexOfLooking >= 0)
if (contains) {
break;
}
MyString_temp = MyString_temp.substring(second + 1);
}
After the while loop, contains has your answer, and indexOfLooking has the location of S.
With Apache Commons you can use the following method:
StringUtils.substringBetween(str, "'");
to get an String[] with all results use this:
StringUtils.substringsBetween(str, "'", "'");

Categories

Resources