运行时,用户从键盘输入表达式(操作数,运算符,操作数),数据和运算符间可能有空白,也可能没有,比如:
32+685
3 * 93
26 /9
可进行加减乘除等简单运算,本想使用Scanner来接受输入,但操作数和运算符连起来时,读取第一个数据(nextInt)都会出错,更是没有办法读取运算符(没有nextChar),并根据此进行相应的运算。
有的类能读取字符,但却没有封装读取数据。
难道这样简单的程序Scanner就没有办法完成吗?还得使用多个类进行读写?
我相信应该是我对Scanner还没有完全理解,希望能得到大家的帮助,谢谢啦~~~
------解决思路----------------------
这是双栈术的方法,我只演示四种基本运算符号。
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
/**
* Created by lxc on 2015/10/5.
*/
public class Evalute {
private Stack<String> ops=new Stack<String>();
private Stack<Double> vals=new Stack<Double>();
public Evalute() {
}
public void cal(String Str){
Queue<String> unit=new LinkedList<String>();
for (int i = 0; i <Str.length(); i++) {
unit.offer(String.valueOf(Str.charAt(i)));
}
for (int i = 0; i <unit.size() ; i++) {
String one=unit.poll();
if (one.equals("(")){
}else if(one.equals("+")){
ops.push(one);
}else if(one.equals("-")){
ops.push(one);
}else if(one.equals("*")){
ops.push(one);
}else if (one.equals("/")){
ops.push(one);
}else if(one.equals(")")){
String op=ops.pop();
double v=vals.pop();
if(one.equals("+")){
v=vals.pop()+v;
}else if ((one.equals("-"))){
v=vals.pop()-v;
}else if (one.equals("*")){
v=vals.pop()*v;
}else if (one.equals("/")){
v=vals.pop()/v;
}
vals.push(v);
}else {
vals.push(Double.parseDouble(one));
}
}
System.out.println(vals.pop());
}
}
------解决思路----------------------
package book.string;
/*
* 表达式解析器
*/
public class ExpressionParser {
//4种标记类型
public static final int NONE_TOKEN = 0; //标记为空或结束符
public static final int DELIMITER_TOKEN = 1; //标记为分隔符
public static final int VARIABLE_TOKEN = 2; //标记为变量
public static final int NUMBER_TOKEN = 3; //标记为数字
//4种错误类型
public static final int SYNTAX_ERROR = 0; //语法错误
public static final int UNBALPARENS_ERROR = 1; //括号没有结束错误
public static final int NOEXP_ERROR = 2; //表达式为空错误
public static final int DIVBYZERO_ERROR = 3; //被零除错误
//针对4种错误类型,定义4个错误提示
public static final String[] ERROR_MESSAGES = {"Syntax Error","Unbalanced Parentheses","No Expression Present","Division by Zero"};
public static final String EOE = "\0"; //表达式的结束标记
private String exp; //表达式字符串
private int expIndex; //解析器当前指针在表达式中的位置
private String token; //解析器当前处理的标记
private int tokenType; //解析器当前处理标记的类型
private double vars[] = new double[26]; //变量的数组
/** 解析一个表达式,返回表达式的值*/
public double evalute(String expStr) throws Exception {
double result;
this.exp = expStr;
this.expIndex = 0;
//获取第一个标记
this.getToken();
if(this.token.equals(EOE)) {
//异常:没有表达式
this.handleError(NOEXP_ERROR);
}
result = this.parseAssign(); //处理赋值语句
//处理完赋值语句,应该就是表达式结束符,如果不是,则返回异常
if(!this.token.equals(EOE)) {
this.handleError(SYNTAX_ERROR);
}
return result;
}
/** 处理赋值语句 */
private double parseAssign() throws Exception {
double result; //结果
int varIndex; //变量下标
String oldToken; //旧标记
int oldTokenType; //旧标记的类型
//如果标记类型是变量
if(this.tokenType == VARIABLE_TOKEN) {
//保存当前标记
oldToken = new String(this.token);
oldTokenType = this.tokenType;
//取得变量的索引,本解析器只支持一个字目的变量
//如果用户的变量字母长度大于1,则取首字母当作变量
varIndex = Character.toUpperCase(this.token.charAt(0)) - 'A';
//获得下一标记
this.getToken();
//如果当前标记不是等号
if(!this.token.equals("=")) {
this.putBack(); //回滚
//不是一个赋值语句,将标记恢复到上一标记
this.token = new String(oldToken);
this.tokenType = oldTokenType;
} else {
//如果当前标记是等号=,即给变量赋值,形式如 a = 3 + 5;
//则计算等号后面表达式的值,然后将得到的值赋给变量
this.getToken();
//因为加减法的优先级最低,所以计算加减法表达式
result = this.parseAddOrSub();
//将表达式的值赋给变量,并存在实例变量vars中
this.vars[varIndex] = result;
return result;
}
}
//如果当前标记类型不是变量,或者不是赋值语句式,则用加减法计算表达式的值
return this.parseAddOrSub();
}
/** 计算加减法表达式 */
private double parseAddOrSub() throws Exception {
char op; //运算符
double result; //结果
double partialResult; //子表达式的结果
result = this.parseMulOrDiv(); //用乘除法计算当前子表达式的值
//如果当前标记的第一个字母是加减号,则继续进行加减法运算
while((op = this.token.charAt(0)) == '+'
------解决思路----------------------
op == '-') {
this.getToken();//取下一标记
//用乘除法计算当前子表达式的值
partialResult = this.parseMulOrDiv();
switch(op) {
case '-':
//如果是减法,则用已处理的子表达式的值减去当前子表达式的值
result = result - partialResult;
break;
case '+':
//如果是加法,则用已处理的子表达式的值加上当前子表达式的值
result = result + partialResult;
break;
}
}
return result;
}
/** 计算乘除法表达式,包括取模运算 */
private double parseMulOrDiv() throws Exception {
char op; //运算符
double result; //结果
double partialResult; //子表达式的结果
result = this.parseExponent(); //用指数计算当前子表达式的值
//如果当前标记的第一个字母是乘除或取模运算符,则继续进行乘除法运算
while((op = this.token.charAt(0)) == '*'
------解决思路----------------------
op == '/'
------解决思路----------------------
op == '%') {
this.getToken();//取下一标记
//用指数计算当前子表达式的值
partialResult = this.parseExponent();
switch(op) {
case '*':
//如果是乘法,则用已处理的子表达式的值乘当前子表达式的值
result = result * partialResult;
break;
case '/':
//如果是除法,判断当前子表达式的值是否为0,如果为0,则抛出被0除异常
//除数不能为0
if(partialResult == 0.0) {
this.handleError(DIVBYZERO_ERROR);
}
//除数不为0,则用已处理的子表达式的值除以当前子表达式的值
result = result / partialResult;
break;
case '%':
//如果是取模运算,也要判断当前子表达式的值是否为0,如果为0,则抛出被0除异常
if(partialResult == 0.0) {
this.handleError(DIVBYZERO_ERROR);
}
//进行取模运算
result = result % partialResult;
break;
}
}
return result;
}
/** 计算指数表达式 */
private double parseExponent() throws Exception {
double result; //结果
double partialResult; //子表达式的结果
double ex; //指数的底数
int t; //指数的幂
result = this.parseUnaryOperator(); //用一元运算计算当前子表达式的值(底数)
//如果当前标记为"^",则为指数计算
if(this.token.equals("^")) {
//获取下一个标记,即获取指数的幂
this.getToken();
partialResult= this.parseExponent();
ex = result;
if(partialResult == 0.0) {
//如果指数年的幂为0,则指数的值为1
result = 1;
} else {
//否则,指数的值为个数为幂的底数相乘的结果
for(t=(int)partialResult-1;t>0;t--) {
result = result * ex;
}
}
}
return result;
}
/** 计算一元运算,+,-,表示正数和复数 */
private double parseUnaryOperator() throws Exception {
double result; //结果
String op; //运算符
op = "";
//如果当前标记为分隔符,且分隔符的值等于+或-
if((this.tokenType == DELIMITER_TOKEN) && this.token.equals("+")
------解决思路----------------------
this.token.equals("-")) {
op = this.token;
this.getToken();
}
//用括号运算计算当前子表达式的值
result = this.parseBracket();
if(op.equals("-")) {
//如果运算符为-,则为负数,将子表达式的值变为负数
result = -result;
}
return result;
}
/** 计算括号运算 */
private double parseBracket() throws Exception {
double result; //结果
//如果当前标记为左括号,则表示是一个括号运算
if(this.token.equals("(") ) {
this.getToken(); //取下一标记
result = this.parseAddOrSub(); //用加减法去处子表达式的值
//如果当前标记不等于右括号,抛出括号不匹配异常
if(!this.token.equals(")")) {
this.handleError(UNBALPARENS_ERROR);
}
this.getToken();//否则取下一标记
} else {
//如果标记不是左括号,表示不是一个括号运算,则用原子元素运算计算子表达式值
result = this.parseAtomElement();
}
return result;
}
/** 计算原子元素运算,包括变量和数字 */
private double parseAtomElement() throws Exception {
double result = 0.0; //结果
switch(this.tokenType) {
case NUMBER_TOKEN:
//如果当前标记类型为数字
try {
//将数字的字符串转换成数字值
result = Double.parseDouble(this.token);
} catch(NumberFormatException exc) {
this.handleError(SYNTAX_ERROR);
}
this.getToken(); //取下一标记
break;
case VARIABLE_TOKEN:
//如果当前标记类型是变量,则取变量的值
result = this.findVar(token);
this.getToken();
break;
default:
this.handleError(SYNTAX_ERROR);
break;
}
return result;
}
/** 根据变量名获取变量的值,如果变量名长度大于1,则只取变量的第一个字符 */
private double findVar(String vname) throws Exception {
// 如果变量名的第一个字符不是字母,则很轻出语法异常
if(!Character.isLetter(vname.charAt(0))) {
handleError(SYNTAX_ERROR);
return 0.0;
}
//从变量数组vars中取出该变量的值
return vars[Character.toUpperCase(vname.charAt(0))-'A'];
}
/** 回滚,将解析器当前指针往前移动到当前标记位置 */
private void putBack() throws Exception {
if(this.token == EOE) {
return;
}
//解析器当前指针往前移动
for(int i=0;i<this.token.length();i++) {
this.expIndex--;
}
}
/** 处理异常 */
private void handleError(int errorType) throws Exception{
// 遇到异常情况时,根据错误类型,取得异常提示信息,将提示信息封装在异常中抛出
throw new Exception(ERROR_MESSAGES[errorType]);
}
/** 获取下一个标记 */
private void getToken() {
// 设置初始值
this.tokenType = NONE_TOKEN;
this.token = "";
//检查表达式是否结束,如果解析器当前指针已经到达了字符串的长度
//则表明表达式已经结束,置当前标记的值为EOE
if(this.expIndex == this.exp.length()) {
this.token = EOE;
return;
}
//跳过表达式中的空白符
while(this.expIndex < this.exp.length() && Character.isWhitespace(this.exp.charAt(this.expIndex))) {
++this.expIndex;
}
//再次检查表达式是否结束
if(this.expIndex == this.exp.length()) {
this.token = EOE;
return;
}
char currentChar = this.exp.charAt(this.expIndex); //取解析器当前指针指向的字符
//如果当前字符是一个分隔符,则认为这是一个分隔符标记
//给当前标记和标记类型赋值,并将指针后移
if(isDelim(currentChar)) {
this.token += currentChar;
this.expIndex++;
this.tokenType = DELIMITER_TOKEN;
} else if(Character.isLetter(currentChar)) {
//如果当前字符是一个字母,则认为是一个变量标记
//将解析器指针向后移,直到遇到一个分隔符,之前的字符都是变量的组成部分
while(!isDelim(currentChar)) {
this.token += currentChar;
this.expIndex++;
if(this.expIndex >= this.exp.length()) {
break;
} else {
currentChar = this.exp.charAt(this.expIndex);
}
}
this.tokenType = VARIABLE_TOKEN; //设置标记类型为变量
} else if(Character.isDigit(currentChar)) {
//如果当前字符是一个数字,则认为是一个数值
//将解析器指针向后移,直到遇到一个分隔符,之前的字符都是数值的组成部分
while(!isDelim(currentChar)) {
this.token += currentChar;
this.expIndex++;
if(this.expIndex >= this.exp.length()) {
break;
} else {
currentChar = this.exp.charAt(this.expIndex);
}
}
this.tokenType = NUMBER_TOKEN; //设置标记类型为数字
} else {
//无法识别的字符,则认为表达式结束
this.token = EOE;
return;
}
}
/**
* 判断一个字符是否为分隔符
* 表达式中的字符包括
* 加+ 减- 乘* 除/ 取模% 指数^ 赋值= 左括号( 右括号)
* @param c
* @return boolean
*/
private boolean isDelim(char c) {
if((" +-/*%^=()".indexOf(c) != -1))
return true;
return false;
}
public static void main(String[] args) throws Exception {
ExpressionParser test = new ExpressionParser();
String exp1 = "a = 5.0";
System.out.println("exp1(\"a = 5.0\") = " + test.evalute(exp1));
String exp2 = "b = 3.0";
System.out.println("exp1(\"b = 3.0\") = " + test.evalute(exp2));
String exp3 = "(a+b) * (a-b)";
System.out.println("exp1(\"(a+b) * (a-b)\") = " + test.evalute(exp3));
String exp4 = "3*5-4/2";
System.out.println("exp1(\"3*5-4/2\") = " + test.evalute(exp4));
String exp5 = "(4-2)*((a+b)/(a-b))";
System.out.println("exp1(\"(4-2)*((a+b)/(a-b))\") = " + test.evalute(exp5));
String exp6 = "5%2";
System.out.println("exp1(\"5%2\") = " + test.evalute(exp6));
String exp7 = "3^2 * 5 + 4";
System.out.println("exp1(\"3^2 * 5 + 4\") = " + test.evalute(exp7));
}
}
------解决思路----------------------
package net.csdn.question;
//http://bbs.csdn.net/topics/391838076
//通过Scanner进行两个数据的简单四则运算.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Scanner;
/*命令行操作.
*Please input the Simple Equation that you want to calculate:(eg: 12.3+63.5)
*23+65.5 23.5 - 96.3
*23+65.5=88.5
*23.5-96.3=-72.8
*All Simple Equation calculated!
*(但是其实是这个程序还是稍微有点BUGGER.比如我将上面的测试写成23+65.523.5 - 96.3那么结果是:
*Please input the Simple Equation that you want to calculate:(eg: 12.3+63.5)
×23+65.523.5 - 96.3
*23+65.523=88.523
*5-96.3=-91.3
*All Simple Equation calculated!
*/
public class SimpleEquationCalculateXP {
public static void main(String[] args) {
// XP:可以将多个需要运算式写在同一行,如:" 23.3 + 36 63.5
// +36",遍历输入的一行数据,计算出可以计算的结果并输出公式直至退出.
// 原功能如下:
// 对于以下情况可以用. " 22.3 + 35.1 ",只要double型数据不拆开即可.
// 另外如果如果输入的内容不符合运算的格式.那么自动退出并输出:All Simple Equation calculated!
System.out.println("Please input the Simple Equation that you want to calculate:(eg: 12.3+63.5)");
Scanner input = new Scanner(System.in);
String regex = "\\s*(\\d+(?:\\.\\d+)?)\\s*([-+*/])\\s*(\\d+(?:\\.\\d+)?)\\s*";
Pattern pattern = Pattern.compile(regex);
String content = input.nextLine();
Matcher matcher = pattern.matcher(content);
double result = 0.0;
while (matcher.find()) {
content = matcher.group();
System.out.print(matcher.group(1) + matcher.group(2) + matcher.group(3) + "=");
result = Calculate(content);
System.out.println(result);
}
input.close();
System.out.println("All Simple Equation calculated!");
}
public static double Calculate(String content) {
double result = 0.0;
String regex = "^\\s*(\\d+(?:\\.\\d+)?)\\s*([-+*/])\\s*(\\d+(?:\\.\\d+)?)\\s*$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
matcher.matches();
String x1 = matcher.group(1);
String operator = matcher.group(2);
String x2 = matcher.group(3);
double d1 = new Double(x1);
double d2 = new Double(x2);
if (operator.equals("+")) {
result = d1 + d2;
} else if (operator.equals("-")) {
result = d1 - d2;
} else if (operator.equals("*")) {
result = d1 * d2;
} else if (operator.equals("/")) {
result = d1 / d2;
}
return result;
}
}