How to split string at operators - java

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

Related

How to split a string and save the 2 characters that I split with?

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());

How to evaluate >9 number in a String expression Java

Life is very easy if the expression has values from 0 to 9 but
If expression = 23+52*5 is input by user then I take it in a String named expression.
Now what I want is that a new String or char Array in such a fashion that:
String s or char[] ch = ['23','+','52','*','5']
so that ch[0] or s.charAt(0) gives me 23 and not 2.
To do so I have tried the following and am stuck on what to do next:
for(int i=0;i<expression.length();i++)
{
int operand = 0;
while(i<expression.length() && sol.isOperand(expression.charAt(i))) {
// For a number with more than one digits, as we are scanning
// from left to right.
// Everytime , we get a digit towards right, we can
// multiply current total in operand by 10
// and add the new digit.
operand = (operand*10) + (expression.charAt(i) - '0');
i++;
}
// Finally, you will come out of while loop with i set to a non-numeric
// character or end of string decrement it because it will be
// incremented in increment section of loop once again.
// We do not want to skip the non-numeric character by
// incrementing it twice.
i--;
/**
* I have the desired integer value but how to put it on a string
* or char array to fulfill my needs as stated above.
**/
// help or ideas for code here to get desired output
}
In the while loop the method isOperand(char) is returning a boolean value true if char provided is >=0 or <=9.
You're going to want a String[] when you break the expression apart. Regex lookbehind/lookahead (Java Pattern Reference) allows you to split a String and keep the delimiters. In this case, your delimiters are the operands. You can use a split pattern like this:
public static void main(String[] args) throws Exception {
String expression = "23+52*5";
String[] pieces = expression.split("(?<=\\+|-|\\*|/)|(?=\\+|-|\\*|/)");
System.out.println(Arrays.toString(pieces));
}
Results:
[23, +, 52, *, 5]
One this to consider, is if your expression contains any spaces then you're going to want to remove them before splitting the expression apart. Otherwise, the spaces will be included in the results. To remove the spaces from the expression can be done with String.replaceAll() like this:
expression = expression.replaceAll("\\s+", "");
The "\\s+" is a regular expression pattern that means a whitespace character: [ \t\n\x0B\f\r]. This statement replaces all whitespace characters with an empty space essentially removing them.
String expr = "23+52*5";
String[] operands = expr.split("[^0-9]");
String[] operators = expr.split("[0-9]+");
This breaks it into:
try using a switch case:
//read first character
switch data
if number : what is it ( 0,1,2,3...?)
save the number
if its an operator
save operator
** 2 the switch has 4 cases for operators and 10 for digits **
// read the next character
again switch
if its a number after a number add both chars into a string
if its an operator "close" the number string and convert it into an int
If you will need some code I will gladly help.
Hope the answer is useful.
for i = 1 ; i = string.length
switch :
case 1,2,3,4,5,6,7,8,9,0 (if its a digit)
x(char) = char(i)
case +,-,*,/ (operator)
y(char) = char(i)
x[1] + x[2] +...x[n] = X(string) // build all the digits saves before the operator into 1 string
convert_to_int(X(string))
You can use regex:
\d+
Will grab any instance of one or more consecutive digits.

Generate new word from wildcard [duplicate]

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

Split a mathematical expression while handling negative numbers with Java

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

Java convert string to int

I have a string. I split and store it as a char array . I am trying to convert it using Integer.parseInt and I get an error. How do I convert String to int?
Here's my code:
String tab[]= null;
tab=pesel.split("");
int temp=0;
for(String tab1 : tab)
{
temp=temp+3*Integer.parseInt(tab1); //error
}
Assuming you have a string of digits (e.g. "123"), you can use toCharArray() instead:
for (char c : pesel.toCharArray()) {
temp += 3 * (c - '0');
}
This avoids Integer.parseInt() altogether. If you want to ensure that each character is a digit, you can use Character.isDigit().
Your error is because str.split("") contains a leading empty string in the array:
System.out.println(Arrays.toString("123".split("")));
[, 1, 2, 3]
Now, there is a trick using negative lookaheads to avoid that:
System.out.println(Arrays.toString("123".split("(?!^)")));
[1, 2, 3]
Although, in any case, I would prefer the approach shown above.
You missed a gap in split method.
tab=pesel.split(" ");

Categories

Resources