Someone please help, How exactly can I take a string and break it up evenly.
for example (41-25) how can I pull the 41 or 25 out instead of getting a seperate 4 and 1.
Whenever I enter a double it registers it as each single digit including the period but not as a whole.
static double evaluate(String expr){
//Add code below
Stack<String> operators = new Stack<String>();
Stack<Double> values = new Stack<Double>();
String[] temp = expr.split("");
Double value = 0.0;
for(int i=0; i< temp.length;i++){
if(temp[i].equals("(")) continue;
else if(temp[i].equals("+")) operators.push(temp[i]);
else if(temp[i].equals("-")) operators.push(temp[i]);
else if(temp[i].equals("*")) operators.push(temp[i]);
else if(temp[i].equals("/")) operators.push(temp[i]);
else if(temp[i].equals(")")) {
String ops = operators.pop();
value = values.pop();
value = operate(values.pop(), value, ops);
System.out.println(value);
values.push(value);
}
else{
System.out.println(temp[i]);
Double current = Double.parseDouble(temp[i]);
values.push(current);
}
}
return 0;
}
I would split the string before and after any operator rather than splitting every character:
static double evaluate(String expr){
//Add code below
...
String[] temp = expr.split("((?<=[\+\-\*\/])|(?=[\+\-\*\/]))"); // Changes "41-25" to ["41", "-", "25"]
This uses regex to split the string using a positive look behind (?<=) and a positive lookahead (?=) with a character set inside for the four operators that you need [\+\-\*\/] (the operators are escaped with a backslash.
Any string will split before and after any operator. If you need more operators, they can be added to the character set.
With Java you could even make your character set a String to remove duplicate code by putting:
String operators = "\\+-\\*/";
String[] temp = expr.split("((?<=[" + operators + "])|(?=[" + operators + "]))";
This method enables you to change what operators to split on easily.
Related
I want to parse a string and get a double value.
For example, I input "65.2 hello".
I want to get "65.2"
Will I?
while(scanner.hasNextLine()) {
String ReadString = scanner.nextLine();
double value = Double.parseDouble(ReadString);
Exception in thread "main" java.lang.NumberFormatException: For input string: "65.2 hello"
at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2054)
at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.base/java.lang.Double.parseDouble(Double.java:549)
at com.company.Main.main(Main.java:18)
Because at least part of the String can't be converted to a double, you need to remove that part of the String before you can use parseDouble on it.
Try this.
Scanner scanner = new Scanner("65.2 hello");
while(scanner.hasNextDouble()) {
double value = scanner.nextDouble();
System.out.println(value);
}
output:
65.2
For a simple string like "65.2 hello" where there is one numerical value within the string then a simple:
String myString = "65.2 hello";
double value = Double.parseDouble(myString.replaceAll("[^(-?\\d+(\\.\\d+)?)]", "").trim());
should be suffice. But, if there is more than one numerical value within the string then you would need to change it up a little, for example:
String myString = "I weigh 90.7185kg and I would like to loose another 10kg. "
+ "My name is Tom, I'm 32 years old.";
String parsable = myString.replaceAll("[^(-?\\d+(\\.\\d+)?)]", " ").trim()
.replaceAll("\\s\\p{Punct}|\\p{Punct}\\s", "");
double[] values = {};
if (!parsable.isEmpty()) {
String[] numbers = parsable.split("\\s+");
values = new double[numbers.length];
for (int i = 0; i < numbers.length; i++) {
values[i] = Double.parseDouble(numbers[i]);
}
}
// Display doubles array into Console Window:
for (int i = 0; i < values.length; i++) {
System.out.println("Value #" + (i + 1) + " in String is: -> " + values[i]);
}
About the Regular Expressions (regex's) used in this line:
String parsable = myString.replaceAll("[^(-?\\d+(\\.\\d+)?)]", " ").trim()
.replaceAll("\\s\\p{Punct}|\\p{Punct}\\s", "");
The .replaceAll("[^(-?\\d+(\\.\\d+)?)]", " ").trim() will replace everything within the String except for signed or unsigned Integer or floating point numerical values with a whitespace. It then trims the outcome of leading and or trailing whitespaces, tabs, etc (if any).
The .replaceAll("\\s\\p{Punct}|\\p{Punct}\\s", ""); will replace any remaining special characters like punctuation that contains a least one leading or one trailing whitespace. When the first replaceAll() above has completed there is most likely going to be straggling periods, etc remaining in the string. We don't want those for splitting the string so this replaceAll() will get rid of those stragglers.
All that should now remain in the string will be numerical values separated by one or more whitespaces. This is where the regex \\s+ used in the String#split() method comes in handy:
String[] numbers = parsable.split("\\s+");
This will split the new string based on one or more whitespaces. So, what is "90.7185 10 32" will be split into a String[] Array consisting of three elements, ["90.7185", "10", "32"]. Each element of this array is now converted to a double data type and added to the double type values[] Array.
I need to validate a string argument if it can be converted to an int Array.
String pattern = "(\\d+[,])+";
String test = "18,32,5,8,10";
test2.matches(pattern2) //returns false as i requires , in the end
Is there any way to ignore last ' , '
Use a group construct to specify that digits should be followed by (, digits) ...
\\d+(?:,\\d+)+
Regex for both array and single element
(\d|\[(\d|,\s*)*])
This regex will work for you (checks for a "valid array") :
public static void main(String[] args) {
String s = "18,32,5,8,10";
System.out.println(s.matches("(?!.*,$)(?!,.*$)(\\d+(?:,|$))+"));
}
Checks and fails for:
multiple continuous commas
comma at beginning
comma at end
You can try
Pattern = "^\d+(,\d+)*$"
text = "10,5,10" (TRUE)
text = "10,5,10," (FALSE)
text = "10,5,10 " (FALSE)
Since I don't know how to use regex and if I were in your place then this would have been my way to do so
String test = "18,32,5,8,10";
String str[]=test.split(",");
int ar[] = new int[str.length];
for(int i = 0; i<ar.length; i++){
ar[i] = Integer.parseInt(str[i]);
}
The problem in this code if any I can see is this that call to parseInt() method must be wrapped in try-catch as it can throw NumberFormatException if your string contains value other than digit and comma(,).
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'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
First time posting so please inform me of how to improve.
I'm working on a program to convert infix notation to postfix and then evaluate. My conversion to postfix went well, but I'm having some trouble with my evaluation. In the code below, when I try to convert the operands into a double variable 'number' they don't maintain their value (see runtime output below). Here is part of the method in question (the print statements are for debugging only).
public boolean evaluatePostfix(StringBuffer postfix)
{
Stack <Double> operand = new Stack <Double>();//stack to hold operand values
double answer = 0; //variable to hold result of expression
boolean error = false; //tests for input error
int pos = 0; //temp veraible stores position in postfix expression
double number = 0; //temp variable to convert char to double. also stores that value for reference
double val1 = 0; //first value for operations
double val2 = 0; //second value for operations
double val3 = 0; //answer for val1 and val2
while (!error && pos < postfix.length())
{
System.out.println(postfix.charAt(pos));
if (postfix.charAt(pos) == ' ')
; //do nothing
else if (Character.isDigit(postfix.charAt(pos)))
{
number = Double.parseDouble(postfix.substring(pos));
System.out.printf ("number = %f", number);
operand.push(number);
}
else
{
val1 = operand.pop();
val2 = operand.pop();
System.out.printf ("val1: %f\tval2: %f\n", val1, val2);
---At runtime--- 1
number = 49.000000
8
number = 56.000000
+
val1: 56.000000
val2: 49.000000
val3 = 105.000000
105.0
You are taking the ASCII value of each character e.g. '1' => 49 and pushing it on to the stack.
Most likely what you want is to use a Scanner to read numbers converted from the text you input.
Replace:
number = postfix.charAt(pos);
with:
number = Double.parseDouble(Character.toString(postfix.charAt(pos)));
The Double.parseDouble method converts the string in double:
Returns a new double initialized to the value represented by the
specified String, as performed by the valueOf method of class Double.
(from Javadoc)
If you split the String with postfix.toString.split(" ") and then iterate on the string[] you will be able to parse also double values (like "8.4567"):
String[] sa = postfix.toString().split(" ");
for (String string : sa) {
.... omissis ...
otherwise your code will be correct only parsing single digit integer values.
Parsing an expression may not be a trivial task. In more complex cases using a parser generator is the only reasonable approach.
In your case, you might do without one:
What are your 'tokens'?
How do you detect the start and end of each token?
Once you have your tokens extracted from the input, what do you do with each of them?
Your tokens appear to be (decimal) numbers and arithmetic operators. - How can you determine the start and end of each? Whitespaces " " between them may make a sufficient delimiter.
Then you can cleanly parse your tokens one at a time: Use Double.parseDouble(...) to parse the numerical tokens and process the operators accordingly.
You may want to have a look at Java's Tokenizer for support in extracting the tokens from the input.