前言
风流要是贤公子,白晰仍为美少年。隐墨同学恋爱了,她爱上了隔壁班的少年,恰同学少年,风华正茂,指点山河,挥斥方遒。隐墨同学彻底的坠入了爱河,一发不可收拾,每天空想着和少年檫出不一样的火花,来一场特殊的经历。让两个人的生存交轨,可谓衣带渐宽终不悔,为伊消得人干瘪啊!!
正巧,少年家电脑上的计算器不能正常利用了,你眼睛一亮,本相只有一个,那就是机会,你快速在书架上找到《HarmonyOS》大喊:如意如意,按我心意
一: 需要办理的问题
1. 小数计算的精度丢失
有计算机根本基础的都清楚:由于数字都是双精度浮点数,在计算机中是二进制存储数据的,因此小数和非安全整数(凌驾整数的安全范围[-Math.pow(2, 53),Math.pow(2, 53)]的数据)在计算过程中会存在精度丢失的情况。
小数运算时:“0.2 + 2.22 = 2.4200000000000004”
2. 中缀表达式转为后缀表达式
隐墨同学提问道,作甚要变革呢,为什么要变,怎样变!
逆波兰表达式又叫做后缀表达式。逆波兰表示法是波兰逻辑学家J・卢卡西维兹于1929年首先提出的一种表达式的表示方法 。厥后,人们就把用这种表示法写出的表达式称作“逆波兰表达式”。逆波兰表达式把运算量写在前面,把算符写在后面。
中缀表达式:就是我们平时用的表达式,好比 1+((2+3)*4)-5这种表达式
“1+((2+3)*4)-5”转换为后缀表达式是”1 2 3 + 4 * + 5 -”,可以发现后缀表达式里没有括号
明显的可以察觉到没有括号,由于计算机并不会去先计算括号里面的,大概根据优先级的去计算你给定的字符串(你看似输入的是表达式,但是计算机是按字符串举行处置惩罚的)
规则:
1. 遇到数字就直接输出到后缀表达式中,遇到操纵符就判定其优先级,并将其压入栈中。
2. 假如栈顶元素的优先级大于即是当前操纵符,则先将栈顶元素弹出并输出到后缀表达式中,再将当前操纵符压入栈中。
3. 假如遇到了左括号,则直接将其压入栈中,假如遇到了右括号,则弹出栈中的元素,直到遇到了左括号为止,并将这些元素输出到后缀表达式中。
4. 将栈中剩余的元素依次弹出,并输出到后缀表达式中。
3. 对于异常信息的处置惩罚
仅限于隐墨同学所发现的,有其他情况可以增补呦!!
1. 参考本技艺机上的计算器,机会发现,当表达式的最后一位为符号位时,你在点击例外一个符号他会自动的举行代替。
2. 对于输入 .3 的效果为 3 大概 ((2)+2 = 4
二:团体的思绪而且代码的实现
1. UI结构(Grid)
不难发现,整个计算器的结构就为网格结构(Grid)
Grid组件为网格容器,其中容器内各条目对应一个GridItem组件
代码如下
- @Styles function KeyBoxStyleOther(){
- .width(60)
- .backgroundColor('#ffe0dddd')
- .height(60)
- .borderRadius(8)
- }
- @Styles function KeyBoxStyle(){
- .width(60)
- .backgroundColor(Color.White)
- .height(60)
- .borderRadius(8)
- }
- const nums:string[] = ['7', '8', '9', '4', '5', '6', '1', '2', '3', '0', '.']
- @Entry
- @Component
- struct Index {
- columnsTemplate: string = '1fr 1fr 1fr 1fr'
- @State rowsTemp: string = '1fr 1fr 1fr 1fr 1fr'
- @State rows: number = 5
- @State expression: string = ''
- @State result: string = '0'
- @State @Watch('aboutToAppear') isShowMore: boolean = false //用于判断是否要更多的的展示
- @State expressionFontSize: number = 40
- @State expressionColor: string = '#000000'
- @State resultFontSize: number = 30
- @State resultColor: string = '#000000'
- aboutToAppear(): void {
- this.JudgeIsMore(this.isShowMore)
- }
- JudgeIsMore(judge: boolean) {
- if (judge == true) {
- this.rowsTemp = '1fr 1fr 1fr 1fr 1fr 1fr'
- this.rows = 6
- } else {
- this.rowsTemp = '1fr 1fr 1fr 1fr 1fr'
- this.rows = 5
- }
- }
- build() {
- Column() {
- Row() {
- Image($r('app.media.three_dot'))
- .width(50)
- .height(50)
- .margin(20)
- .onClick(() => {
- this.isShowMore = !this.isShowMore
- })
- }
- .width('100%')
- .justifyContent(FlexAlign.End)
- .alignItems(VerticalAlign.Top) //位于顶端
- Column() {
- Row() {
- TextInput({ text: this.result })
- .fontSize(lengthSize(this.result))
- .fontColor(this.resultColor)
- .fontWeight(700)
- .textAlign(TextAlign.End)
- .backgroundColor(Color.White)
- .padding({ bottom: 20 })
- .animation({ duration: 500 })
- }
- .padding({ right: 15 })
- .justifyContent(FlexAlign.End)
- .width('100%')
- Divider().width('90%').color(Color.Black).height(20)
- Row() {
- TextInput({ text: this.expression })
- .textAlign(TextAlign.End)
- .backgroundColor(Color.White)
- .fontSize(lengthSize(this.expression))
- .fontColor(this.expressionColor)
- .animation({ duration: 500 })
- }
- .padding({ top: 5, bottom: 5 })
- .justifyContent(FlexAlign.End)
- .width('100%')
- .height(70)
- Grid() {
- //是否展开,根据按钮的不同有不同的情况
- if (this.isShowMore) {
- GridItem() {
- Image($r('app.media.rightbucket'))
- .width(30)
- }.KeyBoxStyleOther()
- .onClick(() => {
- this.expression += '('
- })
- GridItem() {
- Image($r('app.media.leftbucket'))
- .width(30)
- }.KeyBoxStyleOther()
- .onClick(() => {
- this.expression += ')'
- })
- GridItem() {
- Image($r('app.media.percent'))
- .width(30)
- }.KeyBoxStyleOther()
- .onClick(() => {
- this.expression += '!'
- })
- GridItem() {
- Image($r('app.media.mi'))
- .width(30)
- }.KeyBoxStyleOther()
- .onClick(() => {
- this.expression += '^'
- })
- }
- //原有键的布局
- GridItem() {
- Image($r('app.media.C'))
- .width(30)
- }.KeyBoxStyleOther()
- .onClick(() => { //对于数据的全部清除
- this.expression = ''
- this.result = '0'
- })
- GridItem() {
- Image($r('app.media.gf_obelus'))
- .width(30)
- }.KeyBoxStyleOther()
- .onClick(() => {
- this.expression=SymbolRecep(this.expression,'/')
- })
- GridItem() {
- Image($r('app.media.mul'))
- .width(30)
- }.KeyBoxStyleOther()
- .onClick(() => {
- this.expressionFontSize
- this.expression=SymbolRecep(this.expression,'*')
- })
- GridItem() {
- Image($r('app.media.delete_left'))
- .width(40)
- }.KeyBoxStyleOther()
- .onClick(() => { //删除最后一位数据
- this.expression = this.expression.slice(0, this.expression.length - 1)
- this.result =''
- })
- GridItem() {
- Image($r('app.media.jiecheng'))
- .width(30)
- }
- .onClick(() => {
- this.expression=SymbolRecep(this.expression,'%')
- })
- .KeyBoxStyleOther()
- .rowStart(this.rows - 1)
- .rowEnd(this.rows - 1)
- .columnStart(0)
- .columnEnd(0)
- GridItem() {
- Image($r('app.media.minus'))
- .width(30)
- }
- .onClick(() => {
- this.expression=SymbolRecep(this.expression,'-')
- })
- .KeyBoxStyleOther()
- .rowStart(this.rows - 4)
- .rowEnd(this.rows - 4)
- .columnStart(3)
- .columnEnd(3)
- GridItem() {
- Image($r('app.media.plus'))
- .width(30)
- }.KeyBoxStyleOther()
- .onClick(() => {
- this.expression=SymbolRecep(this.expression,'+')
- })
- .rowStart(this.rows - 3)
- .columnStart(3)
- GridItem() {
- Text('=')
- .fontColor(Color.White)
- .fontSize(30)
- .fontWeight(FontWeight.Bold)
- }
- .onClick(() => {
- this.expressionFontSize=lengthSize(this.expression)
- this.resultFontSize=lengthSize(this.result)
- this.result=total(this.expression).toString()
- this.expression=''
- })
- .KeyBoxStyleOther()
- .rowStart(this.rows - 2)
- .rowEnd(this.rows - 1)
- .columnStart(3)
- .height(130)
- .columnEnd(3)
- .backgroundColor('#ffff6b14')
- //循环加载数字键盘
- ForEach(nums, (item: string) => {
- GridItem() {
- Text(item)
- .fontSize(20)
- .fontWeight(700)
- }
- .onClick(() => {
- if(item=='.')
- this.expression=SymbolRecep(this.expression,'.')
- else
- this.expression+=item
- })
- .KeyBoxStyle()
- })
- }
- .rowsTemplate(this.rowsTemp)
- .columnsTemplate(this.columnsTemplate)
- .rowsGap(20)
- .columnsGap(8)
- .width('100%')
- .height(this.isShowMore == false ? '55%' : '65%')
- .animation({ duration: 300, curve: Curve.FastOutSlowIn, delay: 5 })
- .backgroundColor("#ffeeebed")
- .padding({
- bottom: 20,
- top: 20,
- left: 8,
- right: 8
- })
- }
- .layoutWeight(1)
- .justifyContent(FlexAlign.End)
- }
- }
- }
复制代码 举行了相应的扩展
2. 表达式转化和异常处置惩罚
对于数据的处置惩罚代码如下
现在让我们开始分析哈:
2.1 正则表达式
- let tokens: string[] = expression.match(/(\d+(\.\d+)?|\+|-|\*|\/|\%|\^|\(|\)|!)/g) || [];
复制代码 这是一串正则表达式,能起到辨认和分离每一个字符的作用。
正则表达式的界说和作用:正则表达式是一种文本模式,它使用特定的字符序列来形貌、匹配和处置惩罚字符串中的字符组合。正则表达式广泛应用于编程语言和文本处置惩罚工具中,用于执行诸如搜刮、更换、验证和提取等操纵。通过正则表达式,可以快速地对大量文本数据举行复杂的模式匹配和操纵。
小提醒:假如看不懂的话可以可以通过设置日志的方式找BUG!!!!!!
举例对于输入 2*(-3*2)-6,以下为token数组中所存放的数据
2.2 后缀表达式转换
我上述所讲比较的粗糙,具体可以参考 后缀表达式转换
压入栈的时候同时处置惩罚多括号的问题
- while (operations.length > 0) {
- const op = operations.pop()
- if (op !== undefined&&op!='(')
- output.push(op)
- }
复制代码 通过日志可以看出被转化后的表达式
计算机就可以成功的举行辨认和处置惩罚了表达式了
2.3 精度丢失
小数运算时:“0.2 + 2.22 = 2.4200000000000004”,当前示例的办理方法是将小数扩展到整数举行计算,计算完成之后再将效果缩小,计算过程为“(0.2 * 100 + 2.22 * 100) / 100 = 2.42”。
- case '*':
- num1*=100000000000
- num2*=100000000000
- if(num2==0) {
- nums.push(num1/100000000000)
- }
- else{
- nums.push(num2/100000000000 * num1 /100000000000)
- }
- break
复制代码 通过测试发现成功的办理
2.4 结构美化和限制问题
- //保证运算符只出现一次
- function SymbolRecep(expression: string,chara:string): string {
- if (expression[expression.length-1] == '+' || expression[expression.length-1] == '-' ||
- expression[expression.length-1] == 'x' || expression[expression.length-1] == '/' ||
- expression[expression.length-1] == '%' || expression[expression.length-1] == '.') {
- return expression.slice(0, expression.length - 1) + chara
- } else
- return expression + chara
- }
复制代码 假如输入的数字过长,就可以改变字体的巨细,更加得当
- function lengthSize(expression: string): number {
- if(expression.length<12)
- return 40
- else if(expression.length<20)
- return 25
- else
- return 20
- }
复制代码 效果图如下
后言
隐墨累了。她的计算器成功写好了,但是终究入不了少年的眼!!!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |