字符串进行四则运算

本文介绍了一个前端与后端交互的示例,用户在前端输入包含变量和运算符的字符串,后端接收后进行四则运算。进阶版需求增加了根据用户选择的key查询或计算数值,再将结果代入表达式中进行计算。前端界面提供简单的计算符号选择,不支持手动输入。后端Java代码实现了表达式解析和计算。进阶逻辑处理部分负责将变量替换为实际数值并执行计算。

需求:在前端输入字符串,后端(java)接受到后进行四则运算,返回计算结果给前端。

需求进阶:前端选择对应的 key,后端根据key 去做查询 或者 计算后 转换为 对应的数字,然后在将数字带入 字符串中,替换掉key,进行计算最终结果;例如前端输入字符串为: price * num * discNum - surplusMoney  。price ,num,discNum 等这些通用选择,或者 用户主动输入。

前端界面图:

前端界面只能通过选择计算符号,不手工收入

进阶版参考图:

 

 前端代码(按简单版,进阶版同理可得):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
	<style>#ystext{height:300px;width:500px;border:1px solid red;}</style>
</head>
<body>
	<br/><br/>
	<button id="ys1" value="+">+</button>
	<button id="ys2" value="-">-</button>
	<button id="ys3" value="*">*</button>
	<button id="ys4" value="/">/</button>
	<button id="ys4" value="(">(</button>
	<button id="ys4" value=")">)</button>
	<br/><br/>
	<div id="ystext" contenteditable></div>
    <br/><br/>
	<button id="jisuan" >计算</button>
    <script>
		// 定义最后光标对象
        var lastRange;
		// 编辑框点击事件
        document.getElementById('ystext').onclick = function() {
            // 获取选定对象
            var selection = getSelection();
            // 设置最后光标对象
            lastRange = selection.getRangeAt(0);
			
        }
		 // 编辑框按键弹起事件
        document.getElementById('ystext').onkeyup = function() {
            // 获取选定对象
            var selection = getSelection();
            // 设置最后光标对象
            lastRange = selection.getRangeAt(0);
			
        }
		
		 //按钮点击事件
        document.getElementById('ys1').onclick = function(e) {
			var ysvalue = this.value;
			setFocusValue(ysvalue);
		}
		 document.getElementById('ys2').onclick = function() {
			var ysvalue = this.value;
			setFocusValue(ysvalue);
		}
		 document.getElementById('ys3').onclick = function() {
			var ysvalue = this.value;
			setFocusValue(ysvalue);
		}
		 document.getElementById('ys4').onclick = function() {
			 // 获取编辑框对象
			var ysvalue = this.value;
			setFocusValue(ysvalue);
		}
		
		//计算
		document.getElementById('jisuan').onclick = function() {
			 // 获取编辑框对象
			var ysvalue = document.getElementById('ystext').value;
			//调用 ajax 请求后台运算,这里根据自己后端 地址写就好了
			
		}
		
		
		/**
		*给文本框光标的地方插入值
		*/
		function setFocusValue(ysvalue){
			var ystext = document.getElementById('ystext');
            // 编辑框设置焦点
            ystext.focus();
			 // 获取选定对象
            var selection = getSelection();
			if (lastRange) {
                // 存在最后光标对象,选定对象清除所有光标并添加最后光标还原之前的状态
                selection.removeAllRanges();
                selection.addRange(lastRange);
            }
			
			
			if (selection.anchorNode.nodeName == '#text') {
				var jiaText = document.createTextNode(ysvalue);
				 // 如果是文本节点则先获取光标对象
				var range = selection.getRangeAt(0)
				// 获取光标对象的范围界定对象,一般就是textNode对象
				var textNode = range.startContainer;
				// 获取光标位置
				var rangeStartOffset = range.startOffset;
				// 文本节点在光标位置处插入新的表情内容
				textNode.insertData(rangeStartOffset, ysvalue)
				// 光标移动到到原来的位置加上新内容的长度
				range.setStart(textNode, rangeStartOffset + ysvalue.length)
				// 光标开始和光标结束重叠
				range.collapse(true)
				// 清除选定对象的所有光标对象
				selection.removeAllRanges()
				// 插入新的光标对象
				selection.addRange(range)
			}else{
				 // 如果是编辑框范围。则创建表情文本节点进行插入
                var emojiText = document.createTextNode(ysvalue)
                
                if (ystext.childNodes.length > 0) {
                    // 如果文本框的子元素大于0,则表示有其他元素,则按照位置插入表情节点
                    for (var i = 0; i < ystext.childNodes.length; i++) {
					console.log("1112:"+selection.anchorOffset+"==="+ystext.childNodes.length);
                        if (i == selection.anchorOffset) {
                            ystext.insertBefore(emojiText, ystext.childNodes[i])
                        }
                    }
                } else {
                    // 否则直接插入一个表情元素
                    ystext.appendChild(emojiText);
                }
                // 创建新的光标对象
                var range = document.createRange();
                // 光标对象的范围界定为新建的表情节点
                range.selectNodeContents(emojiText);
                // 光标位置定位在表情节点的最大长度
                range.setStart(emojiText, emojiText.length);
                // 使光标开始和光标结束重叠
                range.collapse(true);
                // 清除选定对象的所有光标对象
                selection.removeAllRanges();
                // 插入新的光标对象
                selection.addRange(range);
			}
			
            lastRange = selection.getRangeAt(0);
			
		}
		
		function calcArith(strV){
			if(("+-*/").indexOf(strV.substring(0,1)) >= 0 ){
				strV = strV.substring(1,strV.length);
			}
			
			va regExp = new RegExp("[^(0-9,\+,\\-,\*,\/,\s)]");
			if(regExp.test(strV)){
				alert("非法字符");
				return 0.0;
			}
			return exA(strV);
		}
		
		
	
	</script>
    
</body>
</html>

java  后端代码(按简单版,进阶版同理可得):

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
 
/**
 * Java实现计算表达式
 * 只实现有加减乘除以及括号的运算
 * 例如: 3+12+25*(20-20/4)+10
 * @author GuoBo 2009-3-16
 * @version 1.0
 */
public class CalculateExp
{
    private static HashMap sign = new HashMap();
    /* 将运算符的优先级放入到缓存处理 */
    public CalculateExp()
    {
        sign.put(")", "3");
        sign.put("*", "2");
        sign.put("/", "2");
        sign.put("+", "1");
        sign.put("-", "1");
        sign.put("(", "0");
    }
    /**
     * @param String 输入的表达式
     * @return List 解析后的字符串元素
     * 对输入的字符串进行解析
     * 转换为需要处理的数据
     * 例如:3+12+25*(20-20/4)+10
     * 转换后的结果为:
     * List 元素为 ret = {3,+,12,+,25,*,(,20,-,20,-,20,/,4,),+,10}
     */
    public List transStr(String str)
    {
        List strList = new ArrayList();
         
        /* 获取提出数据的符号串 */
        String tmp = str.replaceAll("\\d*", "");
        /* 记录当前的运算符 */
        String curLet = null;
        /* 记录tmp字符串中第一个运算符的位置 */
        int loc = 0;
        /* 符号串长度 */
        int len = tmp.length();
        for (int i = 0; i < len; i++)
        {
            curLet = tmp.substring(i, i + 1);
            loc = str.indexOf(curLet);
            /* 如果当前处理字符为( 或者 ) */
 
            if (!"".equals(str.substring(0, loc).trim()))
            {
                strList.add(str.substring(0, loc).trim());
            }
            strList.add(str.substring(loc, loc + 1));
            str = str.substring(loc + 1);
        }
        if (0 < str.length())
        {
            strList.add(str.trim());
        }
        return strList;
    }
 
    /**
     * 将表达式从中缀表达式转换为后缀表达式(波兰式)
     * @Param List 解析后的表达式的列表
     * @return String[] 转换后的表达式字符串数组
     */
    public String[] midToEnd(List midList)
    {
        Stack embl = new Stack();
        Stack result = new Stack();
         
        Iterator it = midList.iterator();
        String curStr = null;
        while (it.hasNext())
        {
            curStr = (String) it.next();
             
            /* 确认是否式字符串 */
            if(sign.containsKey(curStr))
            {
                /* 如果符号栈为空 或者符号为( */
                if (0 == embl.size() || "(".equals(curStr))
                {
                    embl.push(curStr);
                }
                else
                {
                    /*如果符号为) 符号栈需要出栈,直到匹配一个(为止 */
                    if(")".equals(curStr))
                    {
                        while(!"(".equals((String)embl.peek()))
                        {
                            if(0 >= embl.size())
                            {
                                return null;
                            }
                            result.push(embl.pop());
                        }
                        embl.pop();
                    }
                    else
                    {
                        int p1 = Integer.parseInt((String) sign.get(curStr));
                        int p2 = Integer.parseInt((String) sign.get(embl.peek()));
                         
                        /* 如果当前字符的优先级大于栈顶符号的优先级 */
                        if (p1 > p2)
                        {
                            embl.push(curStr);
                        }
                        else
                        {
                            while (p1 <= p2 || embl.size() > 0)
                            {
                                result.push(embl.pop());
                                if(0 == embl.size())
                                {
                                    break;
                                }
                                p2 = Integer.parseInt((String) sign.get(embl.peek()));
                            }
                            embl.push(curStr);
                        }
                    }
                }
            }
            else
            {
                result.push(curStr);
            }
        }
         
        while (0 < embl.size())
        {
            result.push(embl.pop());
        }
         
        int len = result.size();
        String[] ret = new String[len];
        for (int i = 0; i < len; i++)
        {
            ret[len - i - 1] = (String) result.pop();
        }
         
        return ret;
    }
     
    /**
     * 解析后缀表达式,返回对应的运算结果
     * @param String[] endStr 转换后的后缀表达式
     * @return Object 返回运算结果 如果表达式有误直接打印"Input Error"
     */
    public Object calculate(String[] endStr)
    {
        int len = endStr.length;
        Stack calc = new Stack();
        double p2;
        double p1;
        for (int i = 0; i < len; i++)
        {
            if (sign.containsKey(endStr[i]))
            {
                try
                {
                    p2 = Double.parseDouble((String) calc.pop());
                    p1 = Double.parseDouble((String) calc.pop());
                    calc.push(String.valueOf(simpleCalc(p1, p2,endStr[i])));
                }
                catch(NumberFormatException ex)
                {
                    ex.printStackTrace();
                    return "Input Error";
                }
                catch(Exception ex)
                {
                    ex.printStackTrace();
                    return "Input Error";
                }
            }
            else
            {
                calc.push(endStr[i]);
            }
        }
         
        if (1 == calc.size())
        {
            return calc.pop();
        }
        else
        {
            return "Input Error";
        }
    }
     
    /**
     * 实现底层的运算函数
     * @param double p1 数字1
     * @param double p1 数字2
     * @param String oper 运算符 +-/*
     */
    public double simpleCalc(double p1, double p2, String oper)
    {
         
        switch(oper.charAt(0))
        {
          case '+':
            return p1 + p2;
          case '-':
            return p1 - p2;
          case '*':
            return p1 * p2;
          case '/':
            return p1 / p2;
          default:
            return p1;
        }
    }
     
    /**
     * 主控函数
     */
    public static void main(String[] args)
    {
        CalculateExp ce = new CalculateExp();
        String tmp = "3+12+25*(20-20/4+10";
        String ret = (String) ce.calculate(ce.midToEnd(ce
                .transStr(tmp)));
        double value = 0;
    try
    {
        value = Double.parseDouble(ret);
    }
    catch (NumberFormatException ex)
    {
        System.out.print(ret);
    }
        System.out.print(value);
    }
}

进阶版逻辑处理:

    /**
	 * 进阶版主控函数
     * str 公式字符串
	 */
	public static String getMonValue(String str) {
		CalculateExp ce = new CalculateExp();
		
		String operate="+-*/()";//定义公式中的符号
		
		
		List<String> newlst =  new ArrayList<String>();
		//遍历获取字段对应值,转换到公式字符串
		String key ="";
		for(int i=0;i<str.length();i++) {
			//判断是否为符号
			if(operate.indexOf(str.substring(i, i+1)) == -1) {
				key = key+str.substring(i, i+1).trim();
			}else {
				if(!"".equals(key)) {
					try {
						//获取数据库映射的 key的 取值,这里自行写转换逻辑
						
                        //将转换后的指替换到字符串中
						newlst.add(sourceValue);
					} catch (Exception e) {
						// TODO 自动生成的 catch 块
						e.printStackTrace();
					}
				}
				//添加符号到集合中
				newlst.add(str.substring(i, i+1));
				key = "";//重置key
			}
		}
		
		//进行四则运算
		String ret = (String) ce.calculate(ce.midToEnd(newlst));
		
		
		return ret;
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值