先看看如何使用栈进行表达式求值:
若还有点困惑,那看看视频讲解吧
3.3.2_栈在表达式求值中的应用_哔哩哔哩_bilibili
计算器页面:
实现代码:
//定义处理输入数据及计算数值的函数
function ParseAndCalculate(expression:string):number {
if(expression.length===0) return 0; //若表达式长度为0,直接返回
let operators: string[] = []; //存放运算符
let num:number[]=[] //存放数值
//进行计算的函数
const applyOperator = (a: number, b: number, op: string): number => {
switch (op) {
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
if(b===0)
{
console.error('输入非法') //若除数为0,则打印错误日志,不返回结果
}
return a / b;
case '%':
return a % b
default: {
console.log(op)
return 0
}
}
}
//定义处理表达式的函数
const parse=(exp:string)=>{
let res:string='' //设置一个空串来存取数字
let i=0 //记录已处理字符的个数
let is_number:boolean=false; //判断是否为数字部分,若不是则将res转化为数字
for(let char of exp) //用for of 循环遍历字符串
{
i++;
if(char==='(') //若为"(",则直接放入operations[],直接进入下一循环
{
operators.push('(')
continue;
}
if(char==='.'&&res.length===0) res+=0 //处理输入为‘.9'类似情况,此时res为空
else if(char==='-'&&res.length===0&&operators[operators.length-1]!==')')
{res+=char;continue} // 处理负数
else if(char==='+'&&num.length===0&&res.length===0) {res+=0}
//处理表达式第一位为‘+’情况
if((char>='0'&&char<='9')||char==='.') //判断是否为数字部分
{
res+=char;
if(i===exp.length) //若为最后一个字符,则需将res转换为数值
{num.push(parseFloat(res))
res=''
}
is_number=true
continue;
}
else if(is_number){ //若上一次处理的字符为数字,但此次不是,则进行转换
num.push(parseFloat(res))
res=''
is_number=false
}
if(char===')') //若为‘)’则开始计算括号内表达式的结果
{
let ope:string=operators.pop() as string
while(ope!=='(')
{
let y:number=num.pop() as number
let x:number=num.pop() as number
num.push(applyOperator(x,y,ope))
//将计算结果存入操作数数组,成为下一次运算的操作数
ope=operators.pop() as string
}
continue
}
if(char==='- '||char==='+'||char==='*'||char==='/'||char==='%'||char==='('||char===')')
{
if(operators.length===0) operators.push(char) //此时为第一个运算符直接入组
else if(char==='*'||char==='/'||char==='%') //根据运算符优先级进行处理
{
if(operators[(operators.length)-1]==='+'||operators[operators.length-1]==='-
'||operators[operators.length-1]==='(')
{
operators.push(char)
}
else if(operators[operators.length-1]==='*'||operators[operators.length- 1]==='/'||operators[operators.length-1]==='%')
{
let ope:string=operators.pop() as string
let y:number=num.pop() as number
let x:number=num.pop() as number
num.push(applyOperator(x,y,ope))
operators.push(char)
}
}
else if(char==='+'||char==='-')
{
if(operators[operators.length-1]!=='(')
{
let ope:string=operators.pop() as string
let y:number=num.pop() as number
let x:number=num.pop() as number
num.push(applyOperator(x,y,ope))
if(operators[operators.length-1]==='-')
{
let ope:string=operators.pop() as string
let y:number=num.pop() as number
let x:number=num.pop() as number
num.push(applyOperator(x,y,ope))
}
operators.push(char)
}
else{
operators.push(char)
}
}
}
}
//处理剩余数据
while (operators.length) {
let x:number=0
let y:number=0
let ope: string = operators.pop() as string
if(ope==='(') continue
if(num.length===1)
{ y=0
x=num.pop() as number
}
else{
y= num.pop() as number
x = num.pop() as number
}
console.log(`${x},${y},${ope}`)
num.push(applyOperator(x, y, ope))
}
}
//调用表达式处理函数
parse(expression);
if(num[0]) //处理最后操作数数组第一个元素即为计算结果
return num[0]
return 0
}
@Extend(Row) function B_row(){
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
}
//定义创建按钮的组件
@Component
struct createButton{
value:number|string=''
f_size:number=40
build() {
Button(`${this.value}`)
.fontSize(this.f_size)
.width(75)
.height(70)
.borderRadius(10)
.backgroundColor("#ff88cd4b")
}
}
class ButtonValue{
value:Array<number|string>=[]
constructor(array:Array<string|number>) {
this.value=array
}
}
//ButtonValue类的数组
const B_V=[
new ButtonValue([7,8,9]),
new ButtonValue([4,5,6]),
new ButtonValue([1,2,3]),
new ButtonValue(['%',0,'.']),
new ButtonValue(['*','/','+']),
]
//程序入口
@Entry
@Component
struct CaculatorPage {
@State F_size:number=20
@State message_s:string='' //保存计算表达式
@State message_r:string='' //保存计算结果
@State input:boolean=true //用于判断是否为输入状态
@State radius:number=20
height_T:number=150 //文本框高度
build() {
Column({space:8}){
Row(){
//显示数值及结果区
Column() {
Text(this.message_s)
.textOverflow({overflow:TextOverflow.MARQUEE})
.width('100%')
.height(this.height_T)
.fontSize(50)
.backgroundColor('#ff79efca')
.shadow({radius:20,color:'#ff04dd91'})
.borderRadius({topLeft:20,topRight:20,bottomLeft:this.radius,bottomRight:this.radius})
.textAlign(TextAlign.End)
.linearGradient({ angle: 45, colors: [['#ff79efca', 0.5], ['#ff93eacf', 0.5],] })
if(!this.input) //输入结束,则显示计算结果
{
Text(this.message_r)
.width('100%')
.textOverflow({ overflow:TextOverflow.MARQUEE})
.height(70)
.fontSize(50)
.backgroundColor('#ff79efca')
.borderRadius({bottomLeft:20,bottomRight:20})
.textAlign(TextAlign.End)
.linearGradient({ angle: 45, colors: [['#ff79efca', 0.8], ['#ff93eacf', 0.8],] })
.animation({duration:100})
.transition({type:TransitionType.All})
}
}
}
.width('100%')
.padding(20)
.backgroundColor('#ccc')
.borderRadius(5)
//键盘部分
Column({space:10}) {
ForEach(B_V,(item:ButtonValue,id)=>{
//采用双层ForEach循环渲染按钮,也可采用Grid网格布局
Row() {
ForEach(item.value, (val: number) => {
createButton({ value: val }).onClick(() => {
this.message_s += val
console.log(`${id}`)
})
})
if(id===0) // 此时为第一行,渲染‘重置’按钮
{
createButton({ value: '重置' ,f_size:this.F_size}).onClick(this.onResetClick.bind(this))
}
if(id===1)
{
createButton({ value: '删除' ,f_size:this.F_size}).onClick(this.onDeleteClick.bind(this))
}
if(id===2)
{
Button(`(`)
.fontSize(28)
.width(40)
.height(70)
.borderRadius(10)
.backgroundColor("#ff88cd4b")
.onClick(()=>{
this.message_s+='('
})
Button(`)`)
.fontSize(28)
.width(40)
.height(70)
.borderRadius(10)
.backgroundColor("#ff88cd4b")
.onClick(()=>{
this.message_s+=')'
})
}
if(id===3)
{
createButton({value:'='}).onClick(()=>{
this.height_T=80
this.radius=0
let a=calculate(this.message_s)
this.message_r=a.toString()
this.input=false
})
}
if(id===4)
{
createButton({value:'-'}).onClick(()=>{
if(this.message_r)
{
this.message_s=this.message_r
}
this.message_s+='-'
})
}
})
}
.width('100%')
.padding(10)
.layoutWeight(1)
.borderRadius(20)
.backgroundColor('#ffdddada')
.justifyContent(FlexAlign.SpaceEvenly)
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
.padding(5)
}
onDeleteClick(){ //点击'删除'按钮时的事件
if(this.message_s.length>0) {
this.input=true
this.height_T=150
this.radius=20
this.message_s = this.message_s.substring(0,this.message_s.length - 1)
}
}
onResetClick(){ //点击'重置'按钮时的事件
if(this.message_s.length>0)
{
this.input=true
this.height_T=150
this.radius=20
this.message_s=this.message_s.substring(0,0)
this.message_r=''}
}