How to Recursively Parse Substrings Inside of Parentheses - java

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?

Related

Why would java won't recognize a character comparision when I try to compare a slash?

I'm trying to do a Java interpreter for a new language and for this I need to tokenize each one of the characters. I found Jasic that is an already developed interpreter developed in Java so I'm using it as a guide. For the tokenizer I'm trying to change the the if statement that define that a character is a comment. Here is the code:
public static List<Token> tokenize(String source) {
List<Token> tokens = new ArrayList<Token>();
int n=0;
String token = "";
TokenizeState state = TokenizeState.DEFAULT;
// Many tokens are a single character, like operators and ().
String charTokens = "\n=+-*/<>()";
TokenType[] tokenTypes = { TokenType.LINE, TokenType.EQUALS,
TokenType.OPERATOR, TokenType.OPERATOR, TokenType.OPERATOR,
TokenType.OPERATOR, TokenType.OPERATOR, TokenType.OPERATOR,
TokenType.LEFT_PAREN, TokenType.RIGHT_PAREN
};
// Scan through the code one character at a time, building up the list
// of tokens.
for (int i = 0; i < source.length(); i++) {
char c = source.charAt(i);
switch (state) {
case DEFAULT:
if (charTokens.indexOf(c) != -1) {
tokens.add(new Token(Character.toString(c),
tokenTypes[charTokens.indexOf(c)]));
} else if (Character.isLetter(c)) {
token += c;
state = TokenizeState.WORD;
} else if (Character.isDigit(c)) {
token += c;
state = TokenizeState.NUMBER;
} else if (c == '"') {
state = TokenizeState.STRING;
} else if (c == '/'){ // This comparision won't work
state = TokenizeState.COMMENT;
}
/* This is how is handled by Jasic
that uses a single quote for comments
else if (c == '\'') {
state = TokenizeState.COMMENT;
}*/
break;
case WORD:
// Here is more code, but not relevant for this question
}
I already tried even comparing the hashcode of the character and the type, also I tried to use Character.valueOf(c) to get only the value and compare it, like this: Character.valueOf(c) == '/' but nothing worked.
I've searched for answers but everything is about backslashes. So, my question is, do you know why it isn't working? or what I'm doing wrong that the if statement isn't accepting the comparision?
/ is a division operator, according to the charTokens and tokenTypes variables.
This means that it was already handled by the charTokens.indexOf(c) != -1 test, hence c can never be / in that else if statement.
Besides, a / is not the start of a comment. // is.

Finding Balanced Parenthesis Involving Math

I've tried to solve this question for the past couple of hours and I just don't understand it. I know there must be a sort of mathematical calculation to calculate this but I don't know how to exactly calculate it. I know this code does not make sense because I'm completely lost, I would appreciate any hints or help for this to help me get closer to the solution.
I asked my professor and he told me a hint about it being similar to a permutation/combination using alphabet such as 26^3 for 3 different combinations but this did not help me much.
What I know:
There are 796 characters for the input given in the string and I must find ALL possible ways that 796 characters can be in a balanced parenthesis form.
Since it must start with '(' and end with ')' there must be 2 brackets for each case. So it can be '()()(xc)(cvs)'. Thus that means the mathematical calculation must involve 2*(something) per char(s) since it has to be balanced.
I need to use the remainder(%) operator to recursively find every case but how do I do that when I take a char in not an int?
What I don't know:
How will I analyze each case? Won't that take a long time or a lot of code without a simple formula to calculate the input?
Would I need a lot of if-statements or recursion?
Question:
Let Σ = {), (}. Let L ⊆ Σ* be the set of strings of correctly balanced parentheses. For example, (())() is in L and (()))( is not in L. Formally, L is defined recursively as follows.
ε ∈ L
A string x ≠ ε is in L if and only if x is of the form (y)z, where y and z are in L.
n is a specific 3 digit number between 0 and 999.
Compute f(n) mod 997
Some facts you might find useful: if n1, n2 is a member of N(natural number) then,
(n1 x n2) mod 997 and
(n1 + n2) mod 997
n = 796 (this is specific for me and this will be the given input in this case)
So I must "compute f(796) mod 997 = ?" using a program. In this case I will simply use java for this question.
Code:
import java.util.*;
public class findBrackets
{
public static void main(String[] args)
{
String n;
int answer = 0;
Scanner input = new Scanner(System.in);
System.out.println("Input String");
n = input.nextLine();
// probably wrong because a string can start as x(d))c(()...
for(int i = 0; i < n; i++)
{
if(n[i] != '(' || n[i] != ')' || n[i] != null || n[i] != " ") {
answer = 2 * (Integer.parseInt(n[i]); // how can i calculate if its a char
// i have to use mod % operator somewhere but I don't know where?
}
}
System.out.println("f(796) mod 997 = " + answer);
}
}
You might find the following fact useful: the number of strings of n pairs of balanced parentheses is given by the nth Catalan number and its exact value is
(2n)! / (n! (n + 1)!)
You should be able to directly compute this value mod 997 by using the hint about how products and sums distribute over modulus.
Hope this helps!
I'm still not quite sure exactly what you're asking, but validating as to whether or not the parentheses are valid placement can be done using the following method. I used a similar one to go through hundred-page papers to ensure all parentheses were closed properly in the old days.
public static boolean isValid(String s) {
int openParens = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
// we found an open paren
openParens++;
} else if (s.charAt(i) == ')') {
// we can close a paren
openParens--;
}
if (openParens < 0) {
// we closed a paren but there was nothing to close!
return false;
}
}
if (openParens > 0) {
// we didn't close all parens!
return false;
}
// we did!
return true;
}
You need to do implement this:
public static void main (String[]args) {
String str = "((1+2)*(3+4))-5";
if(isValid(str)){
expandString(str);
}
}
public static boolean isValid(String s) {
int totalParenthesis = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
totalParenthesis++;
} else if (s.charAt(i) == ')') {
totalParenthesis--;
}
if (totalParenthesis < 0) {
return false;
}
}
if (totalParenthesis != 0) {
return false;
}
return true;
}
private static void expandString(String str) {
System.out.println("Called with : "+str);
if(!(str.contains("("))){
evalueMyExpresstion(str);
return;
}
String copyString=str;
int count=-1,positionOfOpen=0,positionOfClose=0;
for(Character character : str.toCharArray()) {
count++;
if(count==str.toCharArray().length){
evalueMyExpresstion(str);
return;
} else if(character.equals('(')) {
positionOfOpen=count+1;
} else if(character.equals(')')) {
positionOfClose=count;
copyString = str.substring(0, positionOfOpen - 1) + evalueMyExpresstion(
str.substring(positionOfOpen, positionOfClose)) + str.substring(positionOfClose + 1);
System.out.println("Call again with : "+copyString);
expandString(copyString);
return;
}
}
}
private static String evalueMyExpresstion(String str) {
System.out.println("operation : "+str);
String[] operation;
int returnVal =0;
if(str.contains("+")){
operation = str.split("\\+");
returnVal=Integer.parseInt(operation[0])+ Integer.parseInt(operation[1]);
System.out.println("+ val : "+returnVal);
return Integer.toString(returnVal);
} else if (str.contains("*")){
operation = str.split("\\*");
returnVal=Integer.parseInt(operation[0])* Integer.parseInt(operation[1]);
System.out.println("* val : "+returnVal);
return Integer.toString(returnVal);
} else if (str.contains("-")){
operation = str.split("\\-");
returnVal=Integer.parseInt(operation[0])- Integer.parseInt(operation[1]);
System.out.println("- val : "+returnVal);
return Integer.toString(returnVal);
}
System.out.println(str);
return Integer.toString(returnVal);
}
Output looks like:
Called with : ((1+2)*(3+4))-5
operation : 1+2
+ val : 3
Call again with : (3*(3+4))-5
Called with : (3*(3+4))-5
operation : 3+4
+ val : 7
Call again with : (3*7)-5
Called with : (3*7)-5
operation : 3*7
* val : 21
Call again with : 21-5
Called with : 21-5
operation : 21-5
- val : 16

Using recursion to reverse even indices of a String

For this part of my recursive method I need to handle the case of an even length string greater than 2 (as shown in my base cases). My issue is figuring out how to make my recursive case actually approach my base cases. I'm not sure if I did the reversing part correctly either, as I get a Stack Overflow error due to the base cases never being hit.
Here's the method in question. (I will handle the odd Strings after my current 'if' statement. I have "return null;" there at the moment so I can test my even case without the odd.)
EDIT:
Example input: ABCDEF
Example output: EBCDAF
public static String revEven(String inString)
{
String tempString = new String();
if (inString.length() <= 2)
return inString;
if (inString.length() == 3)
{
tempString += inString.charAt(2);
tempString += inString.charAt(1);
tempString += inString.charAt(0);
return tempString;
}
if (inString.length() % 2 == 0)
{
return revEven(inString.substring(0, inString.length() - 1) + inString.charAt(inString.length() - 1));
}
return null;
}
The reason why you get StackOverflowError is that your string doesn't change between recursive calls. In the line where you call the function again you just recreate initial string.
"ABCD" = "ABC" (substring (0,3)) + "D" (charAt(3)) - the same string.
Hint. Don't try to change the string in recursive calls.
Probably, it's better to represent your string as array of chars, change indices in recursive calls and then swap chars in place which are pointed by even indices.
I didn't check corner cases but the idea is below:
public static String runEven(String string) {
char[] array = runEvenImpl(string.toCharArray(), 0, string.length());
return new String(array);
}
public static char[] revEvenImpl(char[] array, int head, int tail) {
if (head == tail)
return array;
if (head % 2 == 0 && tail % 2 == 0)
{
swap(array, head, tail);
}
revEven(array, head+1, tail-1);
}

How to use Java's regex to split nested mathematical equations

I was curious on how it would be possible to split mathematical equations with parenthesis meaningfully using java's string regex. It's hard to explain without an example, one is below.
A generic solution pattern would be appreciated, rather than one which just works for the example provided below.
String s = "(5 + 6) + (2 - 18)";
// I want to split this string via the regex pattern of "+",
// (but only the non-nested ones)
// with the result being [(5 + 6), (2 - 18)]
s.split("\\+"); // Won't work, this will split via every plus.
What I'm mainly looking for is first level splitting, I want a regex check to see if a symbol like "+" or "-" is nested in any form, if it is, don't split it, if it isn't split it. Nesting can be in the form of () or [].
Thank you.
Unfortunately, not with RegEx, you need a library like JEP
If you don't expect splitting nested expressions like ((6 + 5)-4), I have a pretty simple function to split the expressions without using regular expressions :
public static String[] subExprs(String expr) {
/* Actual logic to split the expression */
int fromIndex = 0;
int subExprStart = 0;
ArrayList<String> subExprs = new ArrayList<String>();
again:
while ((subExprStart = expr.indexOf("(", fromIndex)) != -1) {
fromIndex = subExprStart;
int substringEnd=0;
while((substringEnd = expr.indexOf(")", fromIndex)) != -1){
subExprs.add(expr.substring(subExprStart, substringEnd+1));
fromIndex = substringEnd + 1;
continue again;
}
}
/* Logic only for printing */
System.out.println("Original expression : " + expr);
System.out.println();
System.out.print("Sub expressions : [ ");
for (String string : subExprs) {
System.out.print(string + ", ");
}
System.out.print("]");
String[] subExprsArray = {};
return subExprs.toArray(subExprsArray);
}
Sample output :
Original expression : (a+b)+(5+6)+(57-6)
Sub expressions : [ (a+b), (5+6), (57-6), ]
EDIT
For the extra condition of also getting expressions enclosed in [], this code will handle expressions inside both () and [].
public static String[] subExprs(String expr) {
/* Actual logic to split the expression */
int fromIndex = 0;
int subExprStartParanthesis = 0;
int subExprStartSquareBrackets = 0;
ArrayList<String> subExprs = new ArrayList<String>();
again: while ((subExprStartParanthesis = expr.indexOf("(", fromIndex)) > -2
&& (subExprStartSquareBrackets = expr.indexOf("[", fromIndex)) > -2) {
/* Check the type of current bracket */
boolean isParanthesis = false;
if (subExprStartParanthesis == -1
&& subExprStartSquareBrackets == -1)
break;
else if (subExprStartParanthesis == -1)
isParanthesis = false;
else if (subExprStartSquareBrackets == -1)
isParanthesis = true;
else if (subExprStartParanthesis < subExprStartSquareBrackets)
isParanthesis = true;
/* Extract the sub expression */
fromIndex = isParanthesis ? subExprStartParanthesis
: subExprStartSquareBrackets;
int subExprEndParanthesis = 0;
int subExprEndSquareBrackets = 0;
if (isParanthesis) {
while ((subExprEndParanthesis = expr.indexOf(")", fromIndex)) != -1) {
subExprs.add(expr.substring(subExprStartParanthesis,
subExprEndParanthesis + 1));
fromIndex = subExprEndParanthesis + 1;
continue again;
}
} else {
while ((subExprEndSquareBrackets = expr.indexOf("]", fromIndex)) != -1) {
subExprs.add(expr.substring(subExprStartSquareBrackets,
subExprEndSquareBrackets + 1));
fromIndex = subExprEndSquareBrackets + 1;
continue again;
}
}
}
/* Logic only for printing */
System.out.println("Original expression : " + expr);
System.out.println();
System.out.print("Sub expressions : [ ");
for (String string : subExprs) {
System.out.print(string + ", ");
}
System.out.print("]");
String[] subExprsArray = {};
return subExprs.toArray(subExprsArray);
}
Sample Output :
Original expression : (a+b)+[5+6]+(57-6)-[a-b]+[c-d]
Sub expressions : [ (a+b), [5+6], (57-6), [a-b], [c-d], ]
Do suggest improvements in the code. :)
You can't know that you will never get more than one level of parentheses, and you can't analyze recursive syntax with a regular expression, by definition. You need to use or write a parser. Have aloo, around for the Dijkstra Shunting Yard Algorithm, or a recursive descent expression parser, or a library that will do either,

Storing StringBuffer

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).

Categories

Resources