I'm working on an expression calculator in Java. I decided to first write a code for conversion to postfix and then write an reverse polish notation calculator. So far my calculator works great and can handle any expression including operators + - * / %.
The problem I'm having however is that it splits the expression using a space input.split(" ") so this means the expression must be entered ( 4 + ( 2 * ( -2 - 1 ) ) ) * 1.5 when I it should be able to be entered (4+(2*(-2-1)))*1.5.
After hours of tinkering and I now know it cant work regex but would it be able to write a for loop that loops through two tokens of the string at a time and if they both equal an operator then you can assume that the second must be a negative value. Or if the Equation starts with an operator then it must be a negative value? Iterate through the string like this until the second operator gets to the end of the expression?
Here is some code I have been playing with trying to make a start at this but since I'm still quite new to programming I can't seem to get it to work.
String expression = "(4+(2*(-2--16)))*-1.5";
ArrayList<String> tokens = new ArrayList<String>();
String orig = null;
String regex = "[-+/*()]+";
String first = Character.toString(expression.charAt(0));
tokens.add(first);
for (int i = 0; i < expression.length(); i++) {
char x = expression.charAt(i);
String a = Character.toString(x);
if (i >= 1){ //Check i is greater than or equal to 1
char y = expression.charAt(i-1);
String b = Character.toString(y);
if(b.matches(regex) && x == '-'){
orig = a;
}else if(orig != null && orig.equals("-")){
System.out.println(orig + a);
tokens.add(orig + a);
orig = null;
}else{
tokens.add(a);
}
}
}
for(String t:tokens){
System.out.print(t+" ");
}
Thanks for any help, Ciaran.
Edit:
My question is how can I write a method to split a mathematical expression which while splitting can tell the difference '-' as a binary operator and '-' as a unary operator? Am I on the right lines with the idea of iterating through a string and comparing the two tokens? – Ciaran Ashton 6 mins ago
What I am trying to achieve
I want to turn String expression = (4+(2*(-2-1))) into String[] expression = (, 4, (, 2, *, (, -2, -, 1, ), ), )
This is a job for a proper parser generator. The best known ones in the Java world are JavaCC and Antlr. I like to use JFlex paired with JavaCC.
What's nice about them is that you give tokens a different meaning based on the context. So, a minus can mean one thing in one place and something different in another place.
Using a parser is the better solution, but to answer your question as you asked it, you can use this regex, which will pretty much do what you want (not 100% but comes close):
(?<=[\(\)\+\-*\/\^A-Za-z])|(?=[\(\)\+\-*\/\^A-Za-z])
So, you will have to escape it and use it like this:
String input = ...;
String temp[] = input.split("(?<=[\\(\\)\\+\\-*\\/\\^A-Za-z])|(?=[\\(\\)\\+\\-*\\/\\^A-Za-z])");
System.out.println(Arrays.toString(temp));
Input:
7+4-(18/3)/2a^222+1ab
Output:
[7, +, 4, -, (, 18, /, 3, ), /, 2, a, ^, 222, +, 1, a, b]
See it in action here:
http://rubular.com/r/uHAObPwaln
http://ideone.com/GLFmo4
This can be the solution to your problem and problem like this although i have not tested this thoroughly on variety of data but approach is that-- whenever unary operator comes in expression(fully parenthesized expression) it will be preceded by '(' and followed by a number.
String expression = "(4+(2*(-2-1)))*1.5";
List<String> tokens = new ArrayList<String>();
String prev = null;
int c = 0;
for (int i = 0; i < expression.length(); i++) {
char x = expression.charAt(i);
String a = Character.toString(x);
if (i >= 1 && expression.charAt(i - 1) == '(' && x == '-') {
prev = a;
} else {
if (prev != null && prev.equals("-")) {
tokens.add(prev + a);
prev = null;
} else {
tokens.add(a);
}
c++;
}
}
This is a version that only uses regular expressions. It matches your sample input but it won't handle situations where unary operators are placed in front of parentheses or if multiple unary operations are nested (e.g. "--1"):
// expression that matches standard Java number formats
// such as 1234, 12.5, and 1.3E-19
String number = "\\d+(?:\\.\\d+(?:(?:E|e)-?\\d+)?)?";
// expression that matches :
// number
// number with unary operator (deemed unary if preceded by (,-,+,/, or *)
// (,),-,+,/, or *
String token = "(" + number + "|(?<=[(-+/*])-" + number + "|[-+/*()])?";
Pattern p = Pattern.compile(token);
Matcher m = p.matcher("(4+(2*(-2-1)))*1.5");
while (m.find()) {
System.out.println(m.group(0));
}
Okay so after all the great advise from the guys I created a method that will take an input such as -1+2(4+(2*(-2--1)))*-1.5 and split it to an array, such as [-1, +, 2, (, 4, +, (, 2, *, (, -2, -, -1, ), ), ), *, -1.5].
The way the method works is that it splits the input String using regex. With regex I was able to split all the numbers and operators. While this is great it wasn't able to handle negative values. Using regex it would always see - as a binary operator. I needed it to see it as a unary operator so that it could understand that it's a negative value. So what I did was compare each operator with the string that followed it. If this was also an operator I knew that the second one was a unary operator. I then also had to put in an if statement for if the first value was a - and if it was I knew that that was a unary operator.
Here's the code so far. I'm sure there is an easier way to do this using a parser, I just couldn't wrap my head around it.
import java.util.ArrayList;
import java.util.Arrays;
public class expSplit {
public String[] splitExp(String theexp){
ArrayList<String> tokens = new ArrayList<String>();
//System.out.println(theexp);
String expression = theexp.replaceAll("\\s+", "");
//System.out.println(expression);
String tem[] = expression.split("(?<=[-+*/%(),])(?=.)|(?<=.)(?=[-+*/%(),])");
ArrayList<String> temp = new ArrayList<String>(Arrays.asList(tem));
String orig = null;
String regex = "[-+/%*]+";
String first = temp.get(0);
tokens.add(first);
String secound = temp.get(1);
if(first.equals("-")){
tokens.remove(0);
tokens.add(first+secound);
}
for (int i = 0; i < temp.size(); i++) {
String a = temp.get(i);
if (i >= 1){
String b = temp.get(i-1);
if(b.matches(regex) && a.matches("[-+]+")){
String c = temp.get(i-2);
if(c.matches("[-+]+")){
//System.out.println("MATCH");
break;
}else{
//System.out.println("NO MATCH");
orig = a;
}
}else if(orig != null && orig.equals("-")){
tokens.add(orig + a);
orig = null;
}else{
tokens.add(a);
}
}
}
if(first.equals("+")){
tokens.remove(0);
}
if(first.equals("-")){
tokens.remove(1);
}
String[]tokenArray = new String[tokens.size()];
tokenArray = tokens.toArray(tokenArray);
//System.out.print(tokens);
return tokenArray;
}
}
Thanks for the help, Ciaran
Related
I am trying to split a given string using the java split method while the string should be devided by two different characters (+ and -) and I am willing to save the characters inside the array aswell in the same index the string has been saven.
for example :
input : String s = "4x^2+3x-2"
output :
arr[0] = 4x^2
arr[1] = +3x
arr[2] = -2
I know how to get the + or - characters in a different index between the numbers but it is not helping me,
any suggestions please?
You can face this problem in many ways. I´m sure there are clever and fancy ways to split this expression. I will show you the simplest problem-solving process that can help you.
State the problem you need to solve, the input and output
Problem: Split a math expression into subexpressions at + and - signals
Input: 4x^2+3x-2
Output: 4x^2,+3x,-2
Create a pseudo code with some logic you might think works
Given an expression string
Create an empty list of expressions
Create a subExpression string
For each character in the expression
Check if the character is + ou - then
add the subExpression in the list and create a new empty subexpression
otherwise, append the character in the subExpression
In the end, add the left subexpression in the list
Implement the pseudo-code in the programming language of your choice
String expression = "4x^2+3x-2";
List<String> expressions = new ArrayList();
StringBuilder subExpression = new StringBuilder();
for (int i = 0; i < expression.length(); i++) {
char character = expression.charAt(i);
if (character == '-' || character == '+') {
expressions.add(subExpression.toString());
subExpression = new StringBuilder(String.valueOf(character));
} else {
subExpression.append(String.valueOf(character));
}
}
expressions.add(subExpression.toString());
System.out.println(expressions);
Output
[4x^2, +3x, -2]
You will end with one algorithm that works for your problem. You can start to improve it.
Try this code:
String s = "4x^2+3x-2";
s = s.replace("+", "#+");
s = s.replace("-", "#-");
String[] ss = s.split("#");
for (int i = 0; i < ss.length; i++) {
Log.e("XOP",ss[i]);
}
This code replaces + and - with #+ and #- respectively and then splits the string with #. That way the + and - operators are not lost in the result.
If you require # as input character then you can use any other Unicode character instead of #.
Try this one:
String s = "4x^2+3x-2";
String[] arr = s.split("[\\+-]");
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
Personally I like it better to have positive matches of patterns, especially if the split pattern itself is empty.
So for instance you could use a Pattern and Matcher like this:
Pattern p = Pattern.compile("(^|[+-])([^+-]*)");
Matcher m = p.matcher("4x^2+3x-2");
while (m.find()) {
System.out.printf("%s or %s %s%n", m.group(), m.group(1), m.group(2));
}
This matches the start of the string or a plus or minus: ^|[+-], followed by any amount of characters that are not a plus or minus: [^+-]*.
Do note that the ^ first matches the start of the string, and is then used to negate a character class when used between brackets. Regular expressions are tricky like that.
Bonus: you can also use the two groups (within the parenthesis in the pattern) to match the operators - if any.
All this is presuming that you want to use/test regular expressions; generally things like this require a parser rather than a regular expression.
A one-liner for persons thinking that this is too complex:
var expressions = Pattern.compile("^|[+-][^+-]*")
.matcher("4x^2+3x-2")
.results()
.map(r -> r.group())
.collect(Collectors.toList());
I've written a code that works similar to calculator, but it solves cryptarithmetic equations. It works fine with basic operations like +-*/.
Now I added the power and root operation and it doesn't work when I use those two new operations. It seems that the problem is with the way I split the input string. The problem is that it doesn't split the string with "^" operator. Here is the code where the problem occurs:
private void findOperator() {
// TODO Auto-generated method stub
String[] tempString = this.rawInputString.split("");
for(String s : tempString){
if(s.equals("+")){
this.operator = "[+]";
break;
}
else if(s.equals("*")){
this.operator = "[*]";
break;
}
else if(s.equals("-")){
this.operator = s;
break;
}
else if(s.equals("/")){
this.operator = s;
break;
}
else if(s.equals("^")){
this.operator = s;
break;
}
else if(s.equals("sqrt")){
this.operator = s;
break;
}
}
}
public void parseInput(){
String[] tempString = rawInputString.split(this.operator);
this.firstString = tempString[0].split("");
this.firstLetterFirstNumber = this.firstString[0];
String temporarySecondPart = tempString[1];//This is where it says I
//have the problem, but it works fine
//with other operators
this.operator = rawInputString.substring(this.firstString.length,this.firstString.length+1);
tempString = temporarySecondPart.split("=");
this.secondString = tempString[0].split("");
this.firstLetterSecondNUmber = this.secondString[0];
this.result = tempString[1].split("");
this.firstLetterResult = this.result[0];
}
split is using regular expression (regex) as argument. Some characters have special meaning in regex (we call them metacharacters) and ^ is one of them. It usually represent start of string, or can be used to create negative character set like [^a-z] will represent any character which is not in range a and z.
If you want to change ^ into simple literal you need to escape it like
split("\\^")
but safer way would be allowing regex to do escaping for you. To do so use
split(Pattern.quote("^"))
or in your case
split(Pattern.quote(operator)).
You are doing some weird jumping through hoops in that code.
findOperator() splits rawInputString into 1-character strings, then searches for the first +, *, -, /, or ^ (ignoring the non-working sqrt) and assigns it to this.operator as a regex.
You then split rawInputString using that regex. Why?
You just found it in findOperator(), so you know exactly where it is.
Then you begin splitting, and splitting, and splitting...
All that, when all you want to do is parse a string a op b = c?
And you seem to want to save it all in fields:
firstString a as a String[] of 1-character
operator op
secondString b as a String[] of 1-character
result c as a String[] of 1-character
firstLetterFirstNumber First 1-character string in firstString
firstLetterSecondNUmber First 1-character string in secondString
firstLetterResult First 1-character string in result
And no error handling whatsoever, so you get ArrayIndexOutOfBoundsException, instead of some meaningful error.
Just use one regular expression, and all your values are ready for you.
And using toCharArray() will give you the 1-character values as a char[].
String rawInputString = "3√343=7";
String regex = "(.+?)([-+*/^√])(.+?)=(.+)";
Matcher m = Pattern.compile(regex).matcher(rawInputString);
if (! m.matches())
throw new IllegalArgumentException("Bad input: " + rawInputString);
char[] firstString = m.group(1).toCharArray();
String operator = m.group(2);
char[] secondString = m.group(3).toCharArray();
char[] result = m.group(4).toCharArray();
char firstLetterFirstNumber = firstString[0];
char firstLetterSecondNUmber = secondString[0];
char firstLetterResult = result[0];
System.out.println("firstString = " + Arrays.toString(firstString));
System.out.println("operator = " + operator);
System.out.println("secondString = " + Arrays.toString(secondString));
System.out.println("result = " + Arrays.toString(result));
OUTPUT
firstString = [3]
operator = √
secondString = [3, 4, 3]
result = [7]
try this regex out
String abc = "a+b-c*d^f";
String reg = "((?<=[<=|>=|==|\\+|\\*|\\-|<|>|/|=|\\^])|(?=[<=|>=|==|\\+|\\*|\\-|<|>|/|=|\\^]))";
String [] arr = abc.split(reg); //split your String according to Expression
for(String obj : arr)
System.out.println(obj);
Your Output will be like that
a
+
b
-
c
*
d
^
f
Note :- Your Complete Mathematical expression will be split into an array of String just by finding any mathematical expression in row
I know it might be another topic about regexes, but despite I searched it, I couldn't get the clear answer. So here is my problem- I have a string like this:
{1,2,{3,{4},5},{5,6}}
I'm removing the most outside parentheses (they are there from input, and I don't need them), so now I have this:
1,2,{3,{4},5},{5,6}
And now, I need to split this string into an array of elements, treating everything inside these parentheses as one, "seamless" element:
Arr[0] 1
Arr[1] 2
Arr[2] {3,{4},5}
Arr[3] {5,6}
I have tried doing it using lookahead but so far, I'm failing (miserably). What would be the neatest way of dealing with those things in terms of regex?
You cannot do this if elements like this should be kept together: {{1},{2}}. The reason is that a regex for this is equivalent to parsing the balanced parenthesis language. This language is context-free and cannot be parsed using a regular expression. The best way to handle this is not to use regex but use a for loop with a stack (the stack gives power to parse context-free languages). In pseudo code we could do:
for char in input
if stack is empty and char is ','
add substring(last, current position) to output array
last = current index
if char is '{'
push '{' on stack
if char is '}'
pop from stack
This pseudo code will construct the array as desired, note that it's best to loop over the indexes of the chars in the given string as you'll need those to determine the boundaries of the substrings to add to the array.
Almost near to the requirement. Running out of time. Will complete rest later (A single comma is incorrect).
Regex: ,(?=[^}]*(?:{|$))
To check regex validity: Go to http://regexr.com/
To implement this pattern in Java, there is a slight difference. \ needs to be added before { and }.
Hence, regex for Java Input: ,(?=[^\\}]*(?:\\{|$))
String numbers = {1,2,{3,{4},5},{5,6}};
numbers = numbers.substring(1, numbers.length()-1);
String[] separatedValues = numbers.split(",(?=[^\\}]*(?:\\{|$))");
System.out.println(separatedValues[0]);
Could not figure out a regex solution, but here's a non-regex solution. It involves parsing numbers (not in curly braces) before each comma (unless its the last number in the string) and parsing strings (in curly braces) until the closing curly brace of the group is found.
If regex solution is found, I'd love to see it.
public static void main(String[] args) throws Exception {
String data = "1,2,{3,{4},5},{5,6},-7,{7,8},{8,{9},10},11";
List<String> list = new ArrayList();
for (int i = 0; i < data.length(); i++) {
if ((Character.isDigit(data.charAt(i))) ||
// Include negative numbers
(data.charAt(i) == '-') && (i + 1 < data.length() && Character.isDigit(data.charAt(i + 1)))) {
// Get the number before the comma, unless it's the last number
int commaIndex = data.indexOf(",", i);
String number = commaIndex > -1
? data.substring(i, commaIndex)
: data.substring(i);
list.add(number);
i += number.length();
} else if (data.charAt(i) == '{') {
// Get the group of numbers until you reach the final
// closing curly brace
StringBuilder sb = new StringBuilder();
int openCount = 0;
int closeCount = 0;
do {
if (data.charAt(i) == '{') {
openCount++;
} else if (data.charAt(i) == '}') {
closeCount++;
}
sb.append(data.charAt(i));
i++;
} while (closeCount < openCount);
list.add(sb.toString());
}
}
for (int i = 0; i < list.size(); i++) {
System.out.printf("Arr[%d]: %s\r\n", i, list.get(i));
}
}
Results:
Arr[0]: 1
Arr[1]: 2
Arr[2]: {3,{4},5}
Arr[3]: {5,6}
Arr[4]: -7
Arr[5]: {7,8}
Arr[6]: {8,{9},10}
Arr[7]: 11
This question already has answers here:
Returning a list of wildcard matches from a HashMap in java
(3 answers)
Closed 7 years ago.
Im trying to generate a word with a wild card and check and see if this word is stored in the dictionary database. Like "appl*" should return apply or apple. However the problem comes in when I have 2 wild cards. "app**" will make words like appaa, appbb..appzz... instead of apple. The second if condition is just for a regular string that contains no wildcards"*"
public static boolean printWords(String s) {
String tempString, tempChar;
if (s.contains("*")) {
for (char c = 'a'; c <= 'z'; c++) {
tempChar = Character.toString(c);
tempString = s.replace("*", tempChar);
if (myDictionary.containsKey(tempString) == true) {
System.out.println(tempString);
}
}
}
if (myDictionary.containsKey(s) == true) {
System.out.println(s);
return true;
} else {
return false;
}
}
You're only using a single for loop over characters, and replacing all instances of * with that character. See the API for String.replace here. So it's no surprise that you're getting strings like Appaa, Appbb, etc.
If you want to actually use Regex expressions, then you shouldn't be doing any String.replace or contains, etc. etc. See Anubian's answer for how to handle your problem.
If you're treating this as a String exercise and don't want to use regular expressions, the easiest way to do what you're actually trying to do (try all combinations of letters for each wildcard) is to do it recursively. If there are no wild cards left in the string, check if it is a word and if so print. If there are wild cards, try each replacement of that wildcard with a character, and recursively call the function on the created string.
public static void printWords(String s){
int firstAsterisk = s.indexOf("*");
if(firstAsterisk == -1){ // doesn't contain asterisk
if (myDictionary.containsKey(s))
System.out.println(s);
return;
}
for(char c = 'a', c <= 'z', c++){
String s2 = s.subString(0, firstAsterisk) + c + s.subString(firstAsterisk + 1);
printWords(s2);
}
}
The base cause relies on the indexOf function - when indexOf returns -1, it means that the given substring (in our case "*") does not occur in the string - thus there are no more wild cards to replace.
The substring part basically recreates the original string with the first asterisk replaced with a character. So supposing that s = "abcd**ef" and c='z', we know that firstAsterisk = 4 (Strings are 0-indexed, index 4 has the first "*"). Thus,
String s2 = s.subString(0, firstAsterisk) + c + s.subString(firstAsterisk + 1);
= "abcd" + 'z' + "*ef"
= "abcdz*ef"
The * character is a regex wildcard, so you can treat the input string as a regular expression:
for (String word : myDictionary) {
if (word.matches(s)) {
System.out.println(word);
}
}
Let the libraries do the heavy lifting for you ;)
With your approach you have to check all possible combinations.
The better way would be to make a regex out of your input string, so replace all * with ..
Than you can loop over your myDirectory and check for every entry whether it matches the regex.
Something like this:
Set<String> dict = new HashSet<String>();
dict.add("apple");
String word = "app**";
Pattern pattern = Pattern.compile(word.replace('*', '.'));
for (String entry : dict) {
if (pattern.matcher(entry).matches()) {
System.out.println("matches: " + entry);
}
}
You have to take care if your input string already contains . than you have to escape them with a \. (The same for other special regex characters.)
See also
http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html and
http://docs.oracle.com/javase/6/docs/api/java/util/regex/Matcher.html
Im creating a calculator in Java.
If i have the user enter a string such as:
7+4-(18/3)/2
So far i have had to have the user enter a space between each number or operator.
How would i create an array from the given string where the string is split at either number or an operator so in this case the array would be:
[7, +, 4, -, (, 18, /, 3, ), /, 2]
(The array is of type String)
Any help would be really appreciated
Thanks :)
try this:
String[] temp = expression.split("[\s+-\\\(\)]+");
will split on:
white spaces
+ operator
- operator
\ character
( character
) character
You haven't specified what you want to do with the array. If you really want to evaluate the expression, then there are already libraries available for that. You can use one of them. But if you only want an array like the one you have shown, then also I wouldn't suggest to use regex. You can write your own parser method like below:
public static String[] parseExpression(String str) {
List<String> list = new ArrayList<String>();
StringBuilder currentDigits = new StringBuilder();
for (char ch: str.toCharArray()) {
if (Character.isDigit(ch)) {
currentDigits.append(ch);
} else {
if (currentDigits.length() > 0) {
list.add(currentDigits.toString());
currentDigits = new StringBuilder();
}
list.add(String.valueOf(ch));
}
}
if (currentDigits.length() > 0)
list.add(currentDigits.toString());
return list.toArray(new String[list.size()]);
}
Now call it like:
String str = "7+4-(18/3)/2";
System.out.println(Arrays.toString(parseExpression(str)));
and you will get your result.
The way I would do this is just scan the string myself to be honest. You will want to build an operation from the results anyway so you don't really gain anything by using an automated parser/splitter/etc.
Here is a rough sketch of the code:
List<Operations> ops = new ArrayList();
for (int i=0;i<str.length();i++) {
char c = str.get(i);
if (c == '.' || c >= '0' || c<='9') {
// extract a number, moving i onwards as I do
// insert number into ops (new Operation(num))
} else if (c!= ' ') {
Operator operator = operators.get(c);
if (operator == null) {
// Handle invalid input - could just skip it
} else {
// Add operator to ops
}
}
}
You would need to define operators for each of the various symbols.
Once you have done that you have parsed the string out to hold only the important data and compiled a list of what operations they are.
Now you need to work out how to process that list of operations applying correct precedence rules etc :) The simplest way may just be to repeatedly loop through the list each time performing each calculation that is valid that time around.
i.e.
1+2*(3+4)-(4+2)
First pass:
1+2*12-6
Second pass:
1+24-6
Result:
19
My first attempt was to use "\b", but that didn't split -(. After some searching, I came up with this:
(?<=[\(\)\+\-*\/\^A-Za-z])|(?=[\(\)\+\-*\/\^A-Za-z])
So, you will have to escape it and use it like this:
String input = ...;
String temp[] = input.split("(?<=[\\(\\)\\+\\-*\\/\\^A-Za-z])|(?=[\\(\\)\\+\\-*\\/\\^A-Za-z])");
System.out.println(Arrays.toString(temp));
Input:
7+4-(18/3)/2a^222+1ab
Output:
[7, +, 4, -, (, 18, /, 3, ), /, 2, a, ^, 222, +, 1, a, b]
See it in action here:
http://rubular.com/r/uHAObPwaln
http://ideone.com/GLFmo4