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

3097

被折叠的 条评论
为什么被折叠?



