Java一道一眼看起来超级简单的试验题,输入字符串求值

输入一个字符串,求值。

第一次见这个题的时候想当然的联想到学C语言的switch语句。就以为很简单,没想到越看越难。做到最后还是有很多bug。

代码本身很多内容不是由我自己完成的,由于年代久远,不知道仿照谁的,借鉴谁的。如果你是原作者,请尽快联系我!我会赶快注明出处的!

代码:

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class Main
{
	
	static Map<String,Integer> optrOrder;
	static {
	optrOrder=new HashMap<String,Integer>();
	optrOrder.put("(", 0);
	optrOrder.put("*", 1);
	optrOrder.put("/", 1);
	optrOrder.put("%", 1);
	optrOrder.put("+",2);
	optrOrder.put("-",2);
	optrOrder.put("^",3);
	optrOrder.put("#",3);
	}

	public static void main(String[] args){
		List<String> tokens; 
		Scanner sc = new Scanner(System.in);
		String st = sc.next();
		try{
			//词法分析
			tokens=lex(st);

			//中缀转后缀 
			tokens=toRpn(tokens); 

			//计算结果
			System.out.println(calcRpn(tokens));

		}catch(Exception ex){
			ex.printStackTrace();
		} 
	}

	//将输入串转换为操作符串
	
	public static List<String> lex(String sExpres)
	{ 
		List<String> tokens=new ArrayList<String>(); 

		//将表达式分割成符号序列
		String sRegExp="(((?<=^|\\(|\\+|-|\\*|/|%)(\\+|-))?\\d+(\\.\\d+)?)"
				+"|\\(|\\)|\\*|/|\\+|-";
		Pattern p=Pattern.compile(sRegExp);
		Matcher m=p.matcher(sExpres.replaceAll("\\s+","")); 
		while(m.find()){
			tokens.add(m.group());
		}

		tokens.add("#");

		return tokens;
	}

	//将中缀表单时转化为后缀表达式
	
	public static List<String> toRpn(List<String> tokens) 
	throws Exception{
		List<String> rpnList=new ArrayList<String>();
		Stack<String> optrStack=new Stack<String>();

		optrStack.add("^");
		for(String token:tokens){
			if(token.matches("^(\\+|-)?\\d+(\\.\\d+)?$")){
				rpnList.add(token);
			}else{
				outputOptr(token,optrStack,rpnList);
			}
	} 

		if(!optrStack.isEmpty()
				&&optrStack.lastElement().equals("#")){
			return rpnList;
		}else{
			throw new Exception("后缀表达式转化错误!");
		} 
	}

	//计算后缀表达式的值
	
	public static double calcRpn(List<String> rpnTokens)
	throws Exception{
	NumberFormat nf=NumberFormat.getInstance();
	Stack<Double> numStack=new Stack<Double>();

	for (String token : rpnTokens) {
	if (token.matches("^(\\+|-)?\\d+(.\\d+)?$")) {
	token=token.indexOf('+')==0
	?token.substring(1)
	:token;
	numStack.add(nf.parse(token).doubleValue());
	} else {
	doCalcByOptr(token, numStack);
	}
	}

	if (!numStack.isEmpty() && numStack.size() == 1) {
	return numStack.lastElement();
	} else {
	throw new Exception("计算错误!");
	}
	} 

	//将运算符输出到后缀表达式序列.

	public static void outputOptr(String optr,
	Stack<String> optrStack,
	List<String> rpnList) 
	throws Exception{
	String preOptr;

	if(optr.equals("(")){//处理左括号
	optrStack.push(optr);
	return;
	}

	if(optr.equals(")")){//处理右括号 
	while(!optrStack.isEmpty()){
	preOptr=optrStack.pop();
	if(!preOptr.equals("(")){
	rpnList.add(preOptr); 
	}else{
	break;
	}
	}

	if(optrStack.isEmpty()){
	throw new Exception("括号未闭合!");
	}

	return;
	}

	/*按优先级处理其他运算符,若当前运算符优先级较高
	* 直接入栈,否则将栈中运算符出战直至栈顶运算符
	* 低于当前运算符
	*/
	preOptr=optrStack.lastElement();
	if(optrCmp(optr,preOptr)<0){
	optrStack.push(optr);
	}else{
	while(!preOptr.equals("(")
	&&!optrStack.isEmpty()
	&&optrCmp(optr,preOptr)>=0){

	preOptr=optrStack.pop();
	if(!preOptr.equals("^")){
	rpnList.add(preOptr);
	} 
	}
	optrStack.push(optr);
	} 
	}

	// 运算符优先级比较函数,optr1优先级大于optr2返回小于0值,
	// 优先级相等返回0,optr1小于optr2返回大于0值.
	
	public static int optrCmp(String optr1,String optr2){
	int order1=optrOrder.get(optr1);
	int order2=optrOrder.get(optr2);
	return order1-order2;
	}

	//根据运算符对数据栈中的内容进行操作.
	
	public static void doCalcByOptr(String optr,
	Stack<Double> numStack){
	double n1,n2;
	n2=numStack.pop();
	n1=numStack.pop();

	if(optr.equals("+")){
	numStack.push(n1+n2);
	}else if(optr.equals("-")){
	numStack.push(n1-n2);
	}else if(optr.equals("*")){
	numStack.push(n1*n2);
	}else if(optr.equals("/")){
	numStack.push(n1/n2);
	}else if(optr.equals("%")){
	numStack.push(n1%n2);
	}
	} 
}

代码很多忘了。很多是借鉴别个的,所以问我也不一定会。但思路就是把中缀表达式转换为后缀表达式,这个我学过,也忘了,建议自行百度。

代码会存在很多bug,目前我就记得别用 ^ 乘方这个符号。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值