How to separate variables and arrays out of an expression with StringTokenizer? - java

I'm trying to separate the arrays and variables from an expression so that I can populate two ArrayLists with either array names or variables. I am using StringTokenizer. I have the expression broken down, but I am having trouble determining which tokens are array names and which are variables.
public void buildSymbols() {
String s = expr; // input from different part of the program
StringTokenizer st = new StringTokenizer(s, "+-*/[]() ");
while(st.hasMoreElements()){
String temp = st.nextToken();
System.out.println(temp);
}
}
I print temp just to make sure that the expression is being separated, but given an expression such as (varx + vary * varz[(vara + varb[(a + b) * 33])]) / 55 I don't know how to tell that varz and varb are array names, while varx, vary, vara, a, and b are variables.
Any ideas how to do this?

I agree wih EJP: The correct solution would be a specific parser. But if you would be content to recognize which delimitter was found by each call to StringTokenizer.nextToken, you can tell StringTokenizer to return also the delimitters. Also, you'll need to retrieve the next delimitter on every current token (as a lookahead). To do that, it's better to store all the tokens in a list:
public void buildSymbols() {
String s = expr; // input from different part of the program
StringTokenizer st = new StringTokenizer(s, "+-*/[]() ", true);
Set<String> delimiters=new HashSet<String>(Arrays.asList(new String[]{"+","-","*","/","[","]","(",")"," "}));
List<Object> tokens=Collections.list(st);
for(int i=0;i<tokens.size();i++){
String temp = tokens.get(i).toString();
if (delimiters.contains(temp))
{
// It is a delimiter
}
else
{
// It is a term
boolean isAnArray=(isNextTokenAnOpenBracket(tokens, i));
...
}
System.out.println(temp);
}
}
private boolean isNextTokenAnOpenBracket(List<Object> tokens, int currentIndex)
{
return (currentIndex < tokens.size() && "[".equals(tokens.get(1 + currentIndex)));
}

Try the String .split() method. It is an alternative to string tokenizer. You can split a string into an array of smaller strings split by a delimiter, just like StringTokenizer. However, you could do it two separate times, the first being with brackets, and the second with the other symbols. Then you know that the last index of your String arrays are the names of Arrays!
String s = expr;
String[] brackSplit = s.split("\\[");
for (String str : brackSplit) {
String[] finalSplit = str.split("*+-/()");
//finalSplit[finalSplit.length - 1] = Array Name!
}
NOTE: StringTokenizer is becoming deprecated with the new version of Java. The string split() method has become the new "recommended" way of splitting strings by delimiters.

Related

Find match with regex in arraylist

I'm trying to develop a function that reads an ArrayList of string and is capable to find if there exist at least two tuples that have the same values from a set of indices but differ for a supplementary index. I've developed a version of this function by using a RegEx comparison as follow:
public boolean checkMatching(){
ArrayList<String> rows = new ArrayList<String>();
rows.add("7,2,2,1,1");
rows.add("7,3,2,1,1");
rows.add("7,8,1,1,1");
rows.add("8,2,1,3,1");
rows.add("8,2,1,4,1");
rows.add("8,4,5,1,1");
int[] indices = new int[] {2,3};
int supplementaryIndex = 1;
String regex = "";
for(String r : rows){
String[] rt = r.split(",");
regex = "[a-zA-Z0-9,-.]*[,][a-zA-Z0-9,-.]*[,][" + rt[indices[0]] + "][,][" + rt[indices[1]] + "][,][a-zA-Z0-9,-.]*";
for(String r2 : rows){
if(r.equals(r2) == false){
if(Pattern.matches(regex, r2)){
String[] rt2 = r.split(",");
if(rt[supplementaryIndex].equals(rt2[supplementaryIndex]) == false){
return true;
}
}
}
}
}
return false;
}
However, it is very expensive, especially if there are many rows. I've thought to create a more complex RegEx that considers multiple choices (with '|' condition), as follow:
public boolean checkMatching(){
ArrayList<String> rows = new ArrayList<String>();
rows.add("7,2,2,1,1");
rows.add("7,3,2,1,1");
rows.add("7,8,1,1,1");
rows.add("8,2,1,3,1");
rows.add("8,2,1,4,1");
rows.add("8,4,5,1,1");
int[] indices = new int[] {2,3};
int supplementaryIndex = 1;
String regex = "";
for(String r : rows){
String[] rt = r.split(",");
regex += "[a-zA-Z0-9,-.]*[,][a-zA-Z0-9,-.]*[,][" + rt[indices[0]] + "][,][" + rt[indices[1]] + "][,][a-zA-Z0-9,-.]*";
regex += "|"; //or
}
for(String r2 : rows){
if(Pattern.matches(regex, r2)){
//String rt2 = r.split(",");
//if(rt[supplementaryIndex].equals(rt2[supplementaryIndex]) == false){
return true;
//}
}
}
return false;
}
But the problem is that this way I can't compare the supplementary index values. Do you have any suggestions on how to define a regex that can directly satisfy this condition? Or, is it possible to leverage java streams to do this efficiently?
The main problem of your first approach is that you have two nested loops over the same list, which gets you a quadratic time complexity. To recall, that implies that the inner loop’s body gets executed 10,000 times for a list with 100 elements and 1,000,000 times for a list of 1,000 elements, and so on.
It doesn’t help calling Pattern.matches(regex, r2) in the inner loop’s body. That method exist only to support (as delegation target) the String operation r2.matches(r2), a convenience method, to do Pattern.compile(regex).matcher(input).matches() in one go. If you have to apply the same regex multiple times, you should keep and re-use the result of Pattern.compile(regex).
But here, there is no point in using a regex at all. You have already decomposed the string using split and can access each component via a plain array access. Using this starting point to compose a regex to be applied on the string again, is complicated and expensive at the same time.
Just use something like
// return true when at least one string has the same values for indices
// but different value for supplementaryIndex
Map<List<String>,String> map = new HashMap<>();
for(String r : rows) {
String[] rt = r.split(",");
List<String> key = List.of(rt[indices[0]], rt[indices[1]]);
String old = map.putIfAbsent(key, rt[supplementaryIndex]);
if(old != null && !old.equals(rt[supplementaryIndex])) return true;
}
return false;
This loops over the list a single time, extracts the key elements from the array and composes a key for a HashMap. There are various ways to do this. But while it’s tempting to just concatenate these elements like rt[indices[0]] + "," + rt[indices[1]], which would work, using a List is preferable, as it avoids expensive string concatenation.
The code puts the value to check into the map which will return a previous value if this key has been encountered before. If so, the old and new values can be compared and the method can return immediately if they don’t match.
When you are using Java 8, you have to use Arrays.asList(rt[indices[0]], rt[indices[1]]) instead of List.of(rt[indices[0]], rt[indices[1]]).
This can be easily expanded to support variable lengths for indices, by changing
List<String> key = List.of(rt[indices[0]], rt[indices[1]]);
to
List<String> key = Arrays.stream(indices).mapToObj(i -> rt[i]).toList();
or, if you are using a Java version older than 16:
List<String> key
= Arrays.stream(indices).mapToObj(i -> rt[i]).collect(Collectors.toList());

simple mathematical expression parsing

I try to write equals override function. I think I have written right but the problem is that parsing the expression. I have an array type of ArrayList<String> it takes inputs from keyboard than evaluate the result. I could compare with another ArrayList<String> variable but how can I compare the ArrayList<String> to String. For example,
String expr = "(5 + 3) * 12 / 3";
ArrayList<String> userInput = new ArrayList<>();
userInput.add("(");
userInput.add("5");
userInput.add(" ");
userInput.add("+");
userInput.add(" ");
userInput.add("3");
.
.
userInput.add("3");
userInput.add(")");
then convert userInput to String then compare using equals
As you see it is too long when a test is wanted to apply.
I have used to split but It splits combined numbers as well. like 12 to 1 and 2
public fooConstructor(String str)
{
// ArrayList<String> holdAllInputs; it is private member in class
holdAllInputs = new ArrayList<>();
String arr[] = str.split("");
for (String s : arr) {
holdAllInputs.add(s);
}
}
As you expect it doesn't give the right result. How can it be fixed? Or can someone help to writing regular expression to parse it properly as wanted?
As output I get:
(,5, ,+, ,3,), ,*, ,1,2, ,/, ,3
instead of
(,5, ,+, ,3,), ,*, ,12, ,/, ,3
The Regular Expression which helps you here is
"(?<=[-+*/()])|(?=[-+*/()])"
and of course, you need to avoid unwanted spaces.
Here we go,
String expr = "(5 + 3) * 12 / 3";
.
. // Your inputs
.
String arr[] = expr.replaceAll("\\s+", "").split("(?<=[-+*/()])|(?=[-+*/()])");
for (String s : arr)
{
System.out.println("Element : " + s);
}
Please see my expiriment : http://rextester.com/YOEQ4863
Hope it helps.
Instead of splitting the input into tokens for which you don't have a regex, it would be good to move ahead with joining the strings in the List like:
StringBuilder sb = new StringBuilder();
for (String s : userInput)
{
sb.append(s);
}
then use sb.toString() later for comparison. I would not advice String concatenation using + operator details here.
Another approach to this would be to use one of the the StringUtils.join methods in Apache Commons Lang.
import org.apache.commons.lang3.StringUtils;
String result = StringUtils.join(list, "");
If you are fortunate enough to be using Java 8, then it's even easier...just use String.join
String result = String.join("", list);
More details on this approach available here
this makes all the inputs into one string which can then be can be compared against the expression to see if it is equal
String x = "";
for(int i = 0; i < holdAllInputs.length; i++){
x = x + holdAllInputs.get(i);
}
if(expr == x){
//do something equal
}else{
//do something if not equal
}

Java check all characters in string are present in a given string array

I am attempting to create a method that checks every character in userInput to see if they are present in operatorsAndOperands. The issue is that tempbool is always false for all values.
import java.util.*;
public class stringCalculator
{
private String userInput = null;
String[] operatorsAndOperands = {"1","2","3","4","5","6","7","8","9","0","+","-","*","/"};
public stringCalculator(String newInput)
{
userInput = newInput;
}
public boolean checkInput()
{
boolean ifExists = true;
for(int i=0; i<userInput.length(); i++)
{
char currentChar = userInput.charAt(i);
boolean tempbool = Arrays.asList(operatorsAndOperands).contains(currentChar);
if (tempbool == false)
{
ifExists = false;
}
}
return ifExists;
}
}
This is because you have an array of string objects (which you later convert to a list of string objects), but you are checking a char for presence in that array.
Efficiency is also pretty poor here - converting a fixed array to a list on each iteration takes a lot of unnecessary CPU cycles.
A simple solution to this problem is to put all characters in a string, and then check each incoming character against that string:
if ("0123456789+-*/".indexOf(currentChar) >= 0) {
... // Good character
}
Another solution would be making a regex that allows only your characters to be specified, like this:
if (expr.replaceAll("[0-9+/*-]*", "").length() == 0) {
... // Expr contains only valid characters
}
Why don't you declare
String[] operatorsAndOperands = {"1","2","3","4","5","6","7","8","9","0","+","-","*","/"};
as a String, instead of an array of String. Then you can just use the contains method to check the characters against the valid operators.
Declare: char[] operatorsAndOperands; instead of: String[] operatorsAndOperands.
Or add this: String.valueOf(charToCompare) as the "contains" argument.
As has been pointed out, the issue is that you're checking for a char in a list of String objects, so you'll never find it.
You can make this check easier, though, by using a regular expression:
Pattern operatorsAndOperands = Pattern.compile("[0-9+\\-*/]");

Java String to Array

I want to evaluate String like "[1,5] [4,5] [10,6]" in in array.
I'm not quite familiar with the Java regex and the syntax.
String game = "[1,5] [4,5] [10,6]"
Pattern splitter = Pattern.compile("\\[|,|\\]");
splitter.matcher(game);
public String [] gameArray = null;
gameArray = splitter.split(game);
I want to to iterate over each pair of array such as : [0][0] => 1; [0][1] => 5
If you put
StringTokenizer st = new StringTokenizer(game, "[,] ");
while (st.hasMoreTokens())
{
currentNumber = Integer.parseInt(st.nextToken());
// fill array with it
}
It should be what you need, if I understood well
For this purpose you need to split your string.
first of all you need to split on space and after that you need to split on ,(comma).and your third step will be remove brackets So at the end you will get you string into array.
Try,
String game = "[1,5] [4,5] [10,6]";
String[] arry=game.substring(1, game.length()-1).split("\\] +\\[");
List<String[]> twoDim=new ArrayList<>();
for (String string : arry) {
String[] twoArr=string.split(",");
twoDim.add(twoArr);
}
String[][] twoArr=twoDim.toArray(new String[0][0]);
System.out.println(twoArr[0][0]); // 1
System.out.println(twoArr[0][1]); // 5

Java: split; cannot convert string[] to string

I'm trying to set up a program that prompts the user to enter a math equation only containing addition and place it in parentheses. My code is meant to search for these equations and give back the sum of the equation.
The part I am having trouble with is when I try to split the addition signs from the code, and parse it so I can turn it into a int. But when I try to split, I get an error that says cannot convert String[] to String.
Here is the coding I have thus far:
String userinput = in.nextLine();
int parentheses;
int parenthesesclose, parse;
String usersubstring;
String split;
while (parentheses >= 0) {
parentheses = userinput.indexOf("(");
parenthesesclose = userinput.indexOf(")");
usersubstring = userinput.substring(parentheses + 1, parenthesesclose);
split = usersubstring.split(+);
split.trim();
if (split.isdigit) {
parse = Interger.parseInt(split);
}
}
Exactly as the error message tells you, String#split() returns a String[], which is a string array. Change your declaration to this:
String[] split;
You should declare variable split as String[]. split() will return you an array of Strings.
String userinput=in.nextLine();
int parentheses;
int parenthesesclose, parse;
String usersubstring;
String[] split;
while ( parentheses >= 0){
parentheses = userinput.indexOf("(");
parenthesesclose = userinput.indexOf(")");
usersubstring = userinput.substring( parentheses + 1, parenthesesclose);
split = usersubstring.split("+");
}
Method split returns an string array, so you should change the type of your split variable to an array.
Also, the multiply symbol not in brakets.
Is this declaration of variables local? If yes, you should define them, otherwise there are possible errors in the heap.

Categories