【iOS】计算器仿写

计算器

  • 前言
  • 四则运算
  • View层
    • Masonry布局
  • 非法输入的逻辑

前言

前两周进行了计算器的仿写,运用了刚学习的Masonry布局以及MVC框架,同时学习了简单的四则运算,今天撰写博客对计算器的仿写进行一个总结,整理归纳期间遇到的问题和收获。

四则运算

这里我先讲中缀表达式转化为后缀表达式,转化的思路是将数字和小数点直接压入后缀表达式的字符串之中,将符号先压入符号栈,而后根据优先级的顺序来将符号取出来放入后缀表达式之中,当碰到括号时,左括号正常入栈,而右括号则将栈内元素出栈进入后缀表达式之中直到栈空或者栈顶元素为左括号,但是左括号也要出栈,但是不进入后缀表达式之中。
推荐可以看看《数据结构》:中缀表达式转后缀表达式 + 后缀表达式的计算这篇博客,讲解的很详细。
后缀表达式的计算我使用OC中自带的NSDecimalNumber类进行运算。

NSDecimalNumber 是 Objective-C 中用于表示和处理高精度十进制数的类。它是 Foundation 框架的一部分,专门设计用于需要精确计算的场景,比如财务应用和科学计算。

代码展示:

static int n = 0;

typedef struct stack {
    char stack[1000];
    int top;
}Stack;

static char nBolan[1000];

Stack* CreatStack(void) {
    Stack* stk = (Stack*) malloc(sizeof(Stack));
    stk->top = -1;
    return stk;
}

void Push(Stack* obj, char val) {
    obj->stack[++obj->top] = val;
}

void pop(Stack* obj) {
    if(obj->top != -1) {
        obj->top--;
    }
}

char GetTopStack(Stack* obj) {
    if(obj->top!=-1) {
        return obj->stack[obj->top];
    }
    return 0;
}//将内容压入后缀表达式

void zhuanhuan(char a, Stack* obj) {
    if(a == '+' || a == '-') {
        if(obj->stack[obj->top] == '-') {
            while(obj->stack[obj->top] != '(' && obj->top != -1) {
                nBolan[n++] = GetTopStack(obj);
                pop(obj);
            }
            Push(obj, a);
            nBolan[n++] = ',';
        } else if( obj->stack[obj->top] == '(') {
            Push(obj, a);
            nBolan[n++] = ',';
        } else if(obj->stack[obj->top] == '*' || obj->stack[obj->top] == '/') {
            while(obj->stack[obj->top] != '(' && obj->top != -1) {
                nBolan[n++] = GetTopStack(obj);
                pop(obj);
            }//将数字和小数点压入后缀表达式
            Push(obj, a);
            nBolan[n++] = ',';//说明是在乘除一个负数
        } else {
            Push(obj, a);
            nBolan[n++] = ',';//说明前一个是数字
        }
    } else if(a == '*' || a == '/') {
        if (obj->stack[obj->top] == '/') {
            nBolan[n++] = GetTopStack(obj);
                    pop(obj);
                    Push(obj, a);
            nBolan[n++] = ',';
        } else if (obj->stack[obj->top] == '(') {
            Push(obj, a);
            nBolan[n++] = ',';
        } else {
            Push(obj, a);
            nBolan[n++] = ',';
        }
    } else if (a == ')') {
        while(obj->stack[obj->top] != '(') {
            nBolan[n++] = GetTopStack(obj);
            pop(obj);
        }
        pop(obj);
    } else if (a == '(') {
        Push(obj, a);
    } else if (a != '=' && a != ')' && a != '(') {
        nBolan[n++] = a;
    }
    if (a == '=') {
        while(obj->top >= 0) {
            nBolan[n++] = GetTopStack(obj);
            pop(obj);
        }
    }
    printf("%s\n", nBolan);
       
}

double evalRPN(char* tokens, int tokenSize) {
    
    NSMutableArray* stack = [NSMutableArray array];
    for(int i = 0; i < tokenSize; i++) {
        if (tokens[i] == ',' || tokens[i] == '(' || tokens[i] == ')') {
            continue;
        }
        if (tokens[i] == '+') {
            NSDecimalNumber* num2 = [stack lastObject];
            NSLog(@"%@", num2);
            [stack removeLastObject];
            NSDecimalNumber* num1 = [stack lastObject];
            NSLog(@"%@", num1);
            [stack removeLastObject];
            [stack addObject:[num1 decimalNumberByAdding:num2]];
            NSLog(@"%@", [stack lastObject]);
            continue;
        }
        if (tokens[i] == '-') {
            NSDecimalNumber* num2 = [stack lastObject];
            [stack removeLastObject];
            NSDecimalNumber* num1 = [stack lastObject];
            [stack removeLastObject];
            [stack addObject:[num1 decimalNumberBySubtracting:num2]];
            continue;
        }
        if (tokens[i] == '*') {
            NSDecimalNumber* num2 = [stack lastObject];
            [stack removeLastObject];
            NSDecimalNumber* num1 = [stack lastObject];
            [stack removeLastObject];
            [stack addObject:[num1 decimalNumberByMultiplyingBy:num2]];
            continue;
        }
        if (tokens[i] == '/') {
            NSDecimalNumber* num2 = [stack lastObject];
            [stack removeLastObject];
            double a = [num2 doubleValue];
            if(a==0)
            {
                n = 0;
                break;
            }
            NSDecimalNumber* num1 = [stack lastObject];
            [stack removeLastObject];
            [stack addObject:[num1 decimalNumberByDividingBy:num2]];
            continue;
        } else {
            NSMutableString* str = [[NSMutableString alloc] init];
            while((tokens[i] >='0'&& tokens[i]<='9')||tokens[i]=='.') {
                [str appendFormat:@"%c", tokens[i]];
                i++;
            }
            i--;
            NSDecimalNumber* num = [NSDecimalNumber decimalNumberWithString:str];
            [stack addObject:num];
            NSLog(@"%@", num);
        }
    }
    NSLog(@"jieshu");
    NSDecimalNumber* num3=[stack lastObject];
    NSLog(@"%@", num3);
    double a = [num3 doubleValue];
    NSLog(@"%f", a);
    return a;
}

-(double) jisuan:(NSString*) str
{
    Stack* obj = CreatStack();
    n = 0;
    for (int i = 0; i < [str length]; i++) {
        //负数的转化
        if ((i == 0 && [str characterAtIndex:0] == '-') || ([str characterAtIndex:i] == '-' && ([str characterAtIndex:i-1] == '+' || [str characterAtIndex:i-1] == '-' || [str characterAtIndex:i-1] == '*' || [str characterAtIndex:i-1] == '/' || [str characterAtIndex:i-1] == '('))) {
            zhuanhuan('(', obj);
            zhuanhuan('0', obj);
            zhuanhuan('-', obj);//使用添加括号的方式,将负数变换为一个括号内进行0-整数的方式
            i++;
            while (([str characterAtIndex:i] >= '0' && [str characterAtIndex:i] <= '9') || [str characterAtIndex:i] == '.') {
                zhuanhuan([str characterAtIndex:i], obj);
                i++;
            }
            zhuanhuan(')', obj);
            i--;
            continue;
        }
        zhuanhuan([str characterAtIndex:i], obj);
    }
    nBolan[n++] = '\0';
    NSLog(@"%s", nBolan);
    int Size = (int)strlen(nBolan);
    double b =  evalRPN(nBolan, Size);
    NSLog(@"%f",b);
    return b;
}

在实际使用的时候,我发现对于括号内的运算,由于运算时会直接跳过后缀表达式中存在的括号,所以右侧括号不写也可以正常进行运算,相当于自动补全括号一样。

View层

在这里插入图片描述

Masonry布局

在View层中构建计算器的页面,这里我使用了Masonry自动布局进行布局,由于按钮的排列是有规律的,故而使用Masonry进行布局会更加简便,下面展示部分布置按钮的代码。

for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 5; j++) {
            if(i == 0 && j == 4)
            {
                self.btn = [UIButton buttonWithType:UIButtonTypeCustom];
                self.btn.tag = 105;
                [self addSubview:self.btn];
                [self.btn mas_makeConstraints:^(MASConstraintMaker *make) {
                    make.left.mas_equalTo(15);
                    make.top.mas_equalTo(720);
                    make.height.mas_equalTo(80);
                    make.width.mas_equalTo(170);
                }];
                self.btn.layer.cornerRadius = 40;
                self.btn.layer.masksToBounds = YES;
                [self.btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
                [self.btn setTitle:@"0" forState:UIControlStateNormal];
                [self.btn setBackgroundColor:[UIColor darkGrayColor]];
                self.btn.titleLabel.font = [UIFont systemFontOfSize:36];
                [self.btn addTarget:self action:@selector(press:) forControlEvents:UIControlEventTouchUpInside];
                continue;
            }
            if(i == 1 && j == 4)
                continue;
            self.btn = [UIButton buttonWithType:UIButtonTypeCustom];
            self.btn.tag = 101 + i * 5 + j;
            [self addSubview:self.btn];
            [self.btn mas_makeConstraints:^(MASConstraintMaker *make) {
                make.left.mas_equalTo(15 + 90 * i);
                make.top.mas_equalTo(360 + 90 * j);
                make.width.and.height.mas_equalTo(80);
            }];
            self.btn.layer.cornerRadius = 40;
            self.btn.layer.masksToBounds = YES;
            [self.btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
            if(j == 0 && i < 3) {
                [self.btn setTitle:[NSString stringWithFormat:@"%@",arr[i*5+j]] forState:UIControlStateNormal];
                [self.btn setBackgroundColor:[UIColor grayColor]];
            } else if(i < 3 && j < 5) {
                [self.btn setTitle:[NSString stringWithFormat:@"%@",arr[i*5+j]] forState:UIControlStateNormal];
                [self.btn setBackgroundColor:[UIColor darkGrayColor]];
            } else {
                [self.btn setTitle:[NSString stringWithFormat:@"%@",arr[i*5+j]] forState:UIControlStateNormal];
                [self.btn setBackgroundColor:[UIColor orangeColor]];
            }
            self.btn.titleLabel.font = [UIFont systemFontOfSize:36];
            [self.btn addTarget:self action:@selector(press:) forControlEvents:UIControlEventTouchUpInside];
        }
    }
    

上述代码是我对于按钮的排布,我们要注意的是,由于我们要在Controller层对于按钮响应事件进行处理,所以我们需要传值将按钮传递给Controller层,这里我使用的是通知传值,也可以使用协议传值

-(void) press:(UIButton*) btn
{
    NSDictionary *dict =[NSDictionary dictionaryWithObject:btn forKey:@"btn"];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"anniu" object:nil userInfo:dict];
}

这里我使用了UITextField的adjustsFontSizeToFitWidth属性,使用它可以让文本输入框的文字自适应大小。

    self.label.adjustsFontSizeToFitWidth = YES;
    self.label.font = [UIFont systemFontOfSize:72.0];//设置刚开始显示的字体大小
    self.label.minimumFontSize = 36.0;//设置最小的字体大小

非法输入的逻辑

笔者对于非法输入的逻辑是禁止非法输入被成功输入,添加到字符串当中去,即只能输入一个合法的式子去进行运算,所以在输入的时候,通过了大量的BOOL类型以及计数的原则去禁止非法的输入出现,下面通过代码结合来讲解。

在这里插入图片描述

由于我是限制输入,所以我使用多个全局变量来达到我的目的。下面展示三个比较具有代表的限制输入的例子,来展示数字,小数点,符号的限制输入。

case 114://对于数字的限制输入
{
     if(chuyiling) {
         NSUInteger a = [self.model.strNum length];
         [self.model.strNum deleteCharactersInRange:NSMakeRange(0, a)];
         ling = NO;
         chuyiling =NO;
     }//这个情况是限制在出现除以零报错后点击任意的按钮,均清空字符串内容
     if(ling) {
         [self.model.strNum deleteCharactersInRange:NSMakeRange(self.model.strNum.length-1, 1)];
          ling = NO;
     }//这个情况是当出现小数点前有一个零,为了避免出现03的情况,直接删除0,变成3这样才是合理的
     if(kuohaowai) {
          if(xiaoshu == 1) xiaoshu++;
          jia = NO;
          jian = NO;
          cheng = NO;
          chu = NO;
          [self.model.strNum appendFormat:@"3"];
      }//重置符号,同时可以使用小数点
      break;
}
case 115:
{
      if(chuyiling) {
           NSUInteger a = [self.model.strNum length];
           [self.model.strNum deleteCharactersInRange:NSMakeRange(0, a)];
           ling = NO;
           chuyiling =NO;
           chu = YES;
           jia = YES;
           jian = NO;
           cheng = YES;
           kuohaowai = YES;
           ling = NO;
           xiaoshu = 1;
       }
       if(xiaoshu == 2) {
           [self.model.strNum appendFormat:@"."];
           jia = YES;
           jian = YES;
           cheng = YES;
           chu = YES;
           xiaoshu = 0;
           ling = NO;
       }//限制当xiaoshu==2时才可以输入小数点,即小数点之前一定是一个数字
       break;
}
case 116:
{
       if(chuyiling) {
            NSUInteger a = [self.model.strNum length];
            [self.model.strNum deleteCharactersInRange:NSMakeRange(0, a)];
            ling = NO;
            chuyiling =NO;
            chu = YES;
            jia = YES;
            jian = NO;
            cheng = YES;
            kuohaowai = YES;
            ling = NO;
            xiaoshu = 1;
        }
        if(!chu){
            [self.model.strNum appendFormat:@"/"];
            chu = YES;
            jia = YES;
            jian = NO;
            cheng = YES;
            kuohaowai = YES;
            ling = NO;
            xiaoshu = 1;
         }//重置小数点计数为1,满足了小数点后有了符号才能出现小数点的条件,重置符号条件,避免出现多个符号。
         break;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/888686.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

污水排放口细粒度检测数据集,污-水排放口的类型包括10类目标,10000余张图像,yolo格式目标检测,9GB数据量。

污水排放口细粒度检测数据集&#xff0c;污-水排放口的类型包括10类目标&#xff08;1 合流下水道&#xff0c;2 雨水&#xff0c;3 工业废水&#xff0c;4 农业排水&#xff0c;5 牲畜养殖&#xff0c;6 水产养殖&#xff0c;7 地表径流&#xff0c;8 废水处理厂&…

PHP中的HTTP请求:获取taobao商品数据的艺术

在电子商务的世界里&#xff0c;数据是宝贵的资产。对于开发者来说&#xff0c;能够快速准确地获取商品数据是一项重要的技能。PHP作为一种流行的服务器端脚本语言&#xff0c;结合cURL扩展&#xff0c;可以轻松实现HTTP请求&#xff0c;从而获取API数据。本文将介绍如何在PHP中…

使用MTVerseXR SDK实现VR串流

1、概述​ MTVerseXR SDK 是摩尔线程GPU加速的虚拟现实&#xff08;VR&#xff09;流媒体平台&#xff0c;专门用于从远程服务器流式传输基于标准OpenXR的应用程序。MTVerseXR可以通过Wi-Fi和USB流式将VR内容从Windows服务器流式传输到XR客户端设备, 使相对性能低的VR客户端可…

c++(多态)

多态的定义 多态是⼀个继承关系的下的类对象&#xff0c;去调⽤同⼀函数&#xff0c;产⽣了不同的⾏为 ⽐如Student继承了Person。Person对象买票全价&#xff0c;Student对象优惠买票。 多态实现的条件 • 必须指针或者引⽤调⽤虚函数 第⼀必须是基类的指针或引⽤&#xff0c;…

性能测试-JMeter(1)

性能测试工具 主流性能测试工具LoadrunnerJMeter JMeter环境安装JMeter功能概要JDK常用文件目录介绍JMeter元件和组件介绍元件的基本介绍组件的基本介绍 JMeter元件作用域和执行顺序JMeter第一个案例线程组HTTP请求查看结果树 JMeter参数化&#xff08;重点&#xff09;用户定义…

涛思数据库安装和卸载

安装 cd opt/taos/TDengine-server-2.4.0.5 sudo ./install.sh 启动taos​ 安装后&#xff0c;请使用 systemctl 命令来启动 TDengine 的服务进程 systemctl start taosd检查服务是否正常工作&#xff1a; systemctl status taosd 升级 3.0 版在之前版本的基础上&#x…

Vue3 集成 json-editor-vue3

简介 快速编辑json数据&#xff0c;还需要支持全屏编辑&#xff0c;以及json校验。 https://github.com/guyue88/json-editor-vue3 安装依赖 npm install json-editor-vue3 --save 引入 在 main.js中添加 import “jsoneditor”; 全局引入 import Vue from vue import Json…

无人自助超市系统小程序源码开发

随着科技的飞速发展和消费模式的转变&#xff0c;无人自助超市作为一种新兴的商业模式&#xff0c;以其便捷性、高效率以及对“体验式购物”的完美诠释&#xff0c;受到了广泛关注。本文renxb001将深入探讨无人自助超市系统小程序源码开发的核心环节和技术要点。 一、系统需求分…

Electron构建桌面应用程序,服务于项目的自主学习记录(持续更新...

无所畏惧地面对未知&#xff0c;并将其视为成长的机会 大纲官网快速入门1.安装node.js -- 这里推荐用nvm管理2.脚手架创建3.electron 包安装到应用的开发依赖4.创建主进程(main.js)并启动项目1.创建页面2.配置main.js3.启动项目 -- 效果 进阶 -- 基于项目场景功能使用场景一&am…

近年来自动驾驶行业就业与企业需求情况

自动驾驶行业在近年来持续发展&#xff0c;就业情况和企业需求呈现出多样化和复杂化的趋势。 以下是基于我搜索到的资料对自动驾驶行业最新就业情况和企业需求的详细分析&#xff1a; 自动驾驶行业对高端技术人才的需求非常旺盛&#xff0c;尤其是架构工程师、算法工程师等岗…

某乎登录加密以及zseck加密逆向

注意,本文只提供学习的思路,严禁违反法律以及破坏信息系统等行为,本文只提供思路 如有侵犯,请联系作者下架 某乎的登录除了需要通过网易易盾外,登录还需要传额外的加密data参数,某盾的加密可以看我之前的文章,这里着重讲解登录以及后续ck的加密,将最终的的登录采集代码…

通过MySQL Workbench 将 SQL Server 迁移到GreatSQL

通过MySQL Workbench 将 SQL Server 迁移到GreatSQL 一、概述 MySQL Workbench 提供了可以将Microsoft SQL Server的表结构和数据迁移到 GreatSQL 的功能&#xff0c;此次将通过MySQL Workbench将SQL Server的数据迁移到GreatSQL。 本文章只是简单演示一下单张表的迁移&…

【LeetCode】每日一题 2024_10_8 旅行终点站(哈希)

前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动&#xff01; 国庆结束了 . . . 力扣的每日一题也来到了终点站 题目&#xff1a;旅行终点站 代码与解题思路 func destCity(paths [][]string) string { // 国庆结束&#xff0c;旅途到了终点// 今天这道题算是一个小…

【LeetCode: 1870. 准时到达的列车最小时速 | 二分】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

看门狗电路设计

看门狗电路设计 看门狗是什么应用架构图TPV6823芯片功能硬件时序图为什么要一般是要保持200个毫秒左右的这种低电平的时间看门狗电路实际应用与条件 看门狗是什么 硬件看门狗芯片&#xff0c;Watch DogTimer&#xff0c;可用于受到电气噪音、电源故障、静电放电等影响(造成软件…

“炫我”受邀出席虚拟现实及元宇宙产业创新论坛!

当前&#xff0c;新一轮科技革命和产业变革向纵深演进&#xff0c;虚拟现实及元宇宙等相关产业加速发展&#xff0c;催生了新产业新业态新模式&#xff0c;发展潜力巨大、应用前景广阔。 9月27日&#xff0c;由北京市科学技术委员会、中关村科技园区管理委员会&#xff0c;北京…

JavaScript 访问者模式:打造高扩展性的对象结构

一. 前言 在面向对象编程中&#xff0c;访问者模式&#xff08;Visitor Pattern&#xff09;是一种行为设计模式&#xff0c;它允许我们向现有的类结构添加新的操作&#xff0c;而无需修改这些类。这对于需要对类层次结构中的元素进行复杂算法处理的场景非常有用。 本文将详细…

【AI绘画SD教程】Lineart线稿上色和IP-Adapter 人像写真插件实操教学,轻松助你生成多种风格的AI人像大片!SD零基础入门到精通教程

大家好&#xff0c;我是画画的小强 今天给大家分享一下如何用AI绘画工具StableDiffusion当中的 LineArt线稿处理 和 IP-Adapter 实操教学。 本期教程开始之前&#xff0c;请先确保你的电脑已经安装好StableDiffusion这款AI绘图工具&#xff0c;如你还没有安装使用&#xff0c…

最新价值5000元的V2M2引擎传奇源码2024BLUE升级版 团购

最新团购的V2M2引擎源码2024年BLUE升级版 特点优势是最新XE12编辑器&#xff0c;微端&#xff0c;各种自定义UI 无限仿GOM引擎功能 参考地址&#xff1a;最新价值5000元的V2M2引擎传奇源码2024BLUE升级版[原始团购版]_1234FCOM专注游戏工具及源码例子分享下载地址:BlueCodePXL…

适合技术小白入门 AI 编程的六个场景

前言 AI 编程最近特别热闹。 自媒体文章说它很强大&#xff0c;确实身边也会看到技术小白用它做出酷炫作品&#xff0c;令人艳羡。 但你自己用时却常遇到坑&#xff0c;找技术朋友一问听到的回答是“AI 干不了这个、铁定会把你带沟里去”。 谁说得对&#xff1f;技术小白到底能…