【iOS】——仿写计算器
文章目录
- 一、实现思路
- 二、实现方法
- 三、判错处理
一、实现思路
先搭建好MVC框架,接着在各个模块中实现各自的任务。首先要创建好UI界面,接着根据UI界面的元素来与数据进行互动,其中创建UI界面需要用到Masonry布局。

二、实现方法
在calculationView文件中只涉及到UI界面。
首先创建两个UITextField对象,一个用来显示输入到表达式,一个用来输出运算结果,接着创建一个数组用来存放button的名称,接着循环创建button对象即可。
创建button时需要设置button的tag属性,因为后面需要通过button的tag属性来进行逻辑判断。
self.textField01 = [[UITextField alloc] init];
self.textField01.backgroundColor = [UIColor blackColor];
self.textField02 = [[UITextField alloc] init];
self.textField02.backgroundColor = [UIColor blackColor];
self.buttonArray = [NSMutableArray arrayWithObjects:@"AC", @"(", @")", @"/", @"1", @"2", @"3", @"+", @"4", @"5", @"6", @"-", @"7", @"8", @"9", @"*", @"0", @".", @"=", nil];for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {self.calculatorButton = [UIButton buttonWithType:UIButtonTypeCustom];NSString* buttonString = self.buttonArray[i * 4 + j];[self.calculatorButton setTitle:buttonString forState:UIControlStateNormal];self.calculatorButton.titleLabel.font = [UIFont systemFontOfSize:43];self.calculatorButton.titleLabel.textColor = [UIColor whiteColor];self.calculatorButton.backgroundColor = [UIColor grayColor];[self.calculatorButton addTarget:self action:@selector(pressButton:) forControlEvents:UIControlEventTouchUpInside];self.calculatorButton.layer.borderWidth = 2.0;self.calculatorButton.layer.cornerRadius = ButtonSize / 2;self.calculatorButton.layer.masksToBounds = YES;self.calculatorButton.tag = 100 + j + i*4;if (i == 0 && j < 3) {self.calculatorButton.backgroundColor = [UIColor colorWithWhite:0.6 alpha:0.9];self.calculatorButton.titleLabel.textColor = [UIColor blackColor];}if (j == 3) {self.calculatorButton.backgroundColor = [UIColor orangeColor];}[self addSubview:self.calculatorButton];[self.calculatorButton mas_makeConstraints:^(MASConstraintMaker *make) {make.top.equalTo(self).offset(90 + HEIGHT / 6 + HEIGHT / 8 + (ButtonSize + SideSize) * i);make.left.equalTo(self).offset(SideSize + (ButtonSize + SideSize) * j);make.width.equalTo(@ButtonSize);make.height.equalTo(@ButtonSize);}];}}
还需要在当前文件触发button的事件函数,因为要通过button的事件函数将当前button传值到CalculationViewController文件中。
我使用的协议传值进行
定义协议及协议方法
@protocol ButttonDelegate <NSObject>- (void)returnButton:(UIButton*)button;@end
定义代理对象
@property (nonatomic, weak)id<ButttonDelegate>delegate;
button事件函数触发代理方法
- (void)pressButton:(UIButton*)button {[self.delegate returnButton:button];
}
在CalculationViewController中定义协议方法
- (void)returnButton:(UIButton*)button;
在CalculationViewController中设置代理对象
self.calculationView.delegate = self;
在CalculationViewController中实现协议方法
- (void)returnButton:(UIButton*)button {
- NSString* buttonStr = button.titleLabel.text;NSInteger buttonTag = button.tag;if (buttonTag == 100) {self.calculationView.textField01.text = @"";self.calculationView.textField02.text = @"";self.yunsuanStr = [[NSMutableString alloc] init];self.jieguoStr = [[NSString alloc] init];} else if (buttonTag == 118) {//四则运算}//
}
对于四则运算,我使用中缀表达式转后缀表达式,再利用后缀表达式进行计算。中缀转后缀定义一个符号栈,一个结果栈。
char resultStack[100];int resultTop = -1;char operationStack[100];int operationTop = -1;NSString* ocStr = self.yunsuanStr;const char* strs = [ocStr UTF8String];char str[1000] ;strcpy(str, strs) ;int length = (int)strlen(str);
后缀进行四则运算时定义一个新栈。
double Stack[100];int StackTop = -1;char* token = strtok(resultStack, " ");while (token != NULL) {if (strcmp(token, "+") == 0) {double a = Stack[StackTop--];double b = Stack[StackTop--];double c = b + a;Stack[++StackTop] = c;}else if (strcmp(token, "-") == 0) {double a = Stack[StackTop--];double b = Stack[StackTop--];double c = b - a;Stack[++StackTop] = c;}else if (strcmp(token, "*") == 0) {double a = Stack[StackTop--];double b = Stack[StackTop--];double c = b * a;Stack[++StackTop] = c;}else if (strcmp(token, "/") == 0) {double a = Stack[StackTop--];double b = Stack[StackTop--];double c = b / a;Stack[++StackTop] = c;}else if (strcmp(token, "!") == 0) {double c = Stack[StackTop--];c = -c;Stack[++StackTop] = c;}else {double num = atof(token);Stack[++StackTop] = num;}token = strtok(NULL, " ");}double result = Stack[StackTop--];
这里使用了atof()函数可以将字符串中的数字识别为double类型的浮点数。使用strtok()函数将结果栈的元素通过空格分割方便进行识别和运算。
对于负数的运算,我是将与“(”相邻的“-”转换为“!”,并用“!”进行负数转变,其中需要将“!“的优先级设置为最高
int Compare(char str) {if (str == '(' || str == ')') {return 0;}else if (str == '+' || str == '-') {return 1;}else if (str == '*' || str == '/') {return 2;} else if (str == '!') {return 3;} else {return -1;}
}
接着在输入字符串时进行识别
for (int i = 0; i < length; ++i) {if (str[i] == '(' && str[i + 1] == '-') {str[i + 1] = '!';}}
三、判错处理
对于括号匹配问题,我使用栈来处理,当读到“(”则入栈,读到“)”则栈顶元素出栈,最后判断栈是否为空即可。
- (int)kuoHaoMatch:(NSMutableString*)mutableString {const char* cstr = [mutableString UTF8String];int length = (int)strlen(cstr);char stack[100];int stackTop = -1;for (int i = 0; i < length; i++) {if (cstr[i] == '(') {stack[++stackTop] = cstr[i];}if (cstr[i] == ')') {stack[stackTop--];}}if (stackTop == -1) {return 1;}return 0;
}
对于符号匹配问题,两个运算符不能相邻,第一个位置不能为运算符(-除外),最后一个位置不能为运算符
- (int)fuHaoMatch:(NSMutableString*)mutableString {const char* cstr = [mutableString UTF8String];int length = (int)strlen(cstr);if (cstr[0] == '*' || cstr[0] == '/' || cstr[0] == '+') {return 0;}for (int i = 0; i < length; i++) {if ((cstr[i] == '*' && cstr[i+1] == '/') || (cstr[i] == '/' && cstr[i+1] == '*')) {return 0;}if ((cstr[i] == '*' && cstr[i+1] == '-') || (cstr[i] == '*' && cstr[i+1] == '+')) {return 0;}if ((cstr[i] == '/' && cstr[i+1] == '-') || (cstr[i] == '/' && cstr[i+1] == '+')) {return 0;}if ((cstr[i] == '+' && cstr[i+1] == '/') || (cstr[i] == '+' && cstr[i+1] == '*')) {return 0;}if ((cstr[i] == '-' && cstr[i+1] == '/') || (cstr[i] == '-' && cstr[i+1] == '*')) {return 0;}if ((cstr[i] == '-' && cstr[i+1] == '-') || (cstr[i] == '-' && cstr[i+1] == '+')) {return 0;}if ((cstr[i] == '+' && cstr[i+1] == '+') || (cstr[i] == '+' && cstr[i+1] == '-')) {return 0;}}if (cstr[length - 1] == '+' || cstr[length - 1] == '-' ||cstr[length - 1] == '*' || cstr[length - 1] == '/') {return 0;}return 1;
}
对于数字和括号的相邻问题,数字后不能直接跟左括号,右括号不能直接跟数字
- (int)numberAndkuoHao:(NSMutableString*)mutableString {const char* cstr = [mutableString UTF8String];int length = (int)strlen(cstr);int flag = 0;for (int i = 0; i < length; i++) {if ((cstr[i]>= '0' && cstr[i] <= '9') &&cstr[i+1] == '(') {flag++;}if (cstr[i] == ')' && (cstr[i + 1]>= '0' && cstr[i + 1] <= '9')) {flag++;}}if (flag == 0) {return 1;}return 0;
}
对于只有括号没有数字的问题,直接遍历整个字符串如果有数字则标志变量加一,最后判断标志变量
- (int)numberJudge:(NSMutableString*)mutableString {const char* cstr = [mutableString UTF8String];int length = (int)strlen(cstr);int flag = 0;for (int i = 0; i < length; i++) {if (cstr[i]>= '0' && cstr[i] <= '9') {flag++;}}if (flag != 0) {return 1;}return 0;;
}
对于除零问题
if ([self.jieguoStr isEqualToString:@"nan"]) {self.jieguoStr = @"错误";}if ([self.jieguoStr isEqualToString:@"inf"]) {self.jieguoStr = @"错误";}
对于小数点异常处理
int pointFlag = 0;
for (int i = 0; i < resultTop; i++) {if (resultStack[i] == '.') {for (int j = i + 1; resultStack[j] != ' '; j++) {if (resultStack[j] == '.') {pointFlag++;}}}}if (pointFlag != 0) {self.jieguoStr = @"错误";pointFlag = 0;}
对于如何删除多余的零
NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithString: self.jieguoStr];NSDecimalNumberHandler *roundHandler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundUp scale:8 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];NSDecimalNumber *roundedNumber = [number decimalNumberByRoundingAccordingToBehavior:roundHandler];self.jieguoStr = [roundedNumber stringValue];
相关文章:
【iOS】——仿写计算器
文章目录 一、实现思路二、实现方法三、判错处理 一、实现思路 先搭建好MVC框架,接着在各个模块中实现各自的任务。首先要创建好UI界面,接着根据UI界面的元素来与数据进行互动,其中创建UI界面需要用到Masonry布局。 二、实现方法 在calcu…...
公安机关警务vr综合实战模拟训练提高团队合作能力
公安出警VR虚拟仿真培训软件是VR公司利用VR虚拟现实和web3d开发技术,对警务执法过程中可能发生的各种场景进行还原、模拟、演练,结合数据分析,实施量化考核,提高学员的心理承压、应急处突、遇袭反应和临危处置综合能力。 公安出警…...
MySQL-1(12000字详解)
一:数据库的引入 数据库在我们以后工作中是一个非常常用的知识,数据库用来存储数据,但是有些同学可能就会疑惑了,存储数据用文件就可以了,为什么还要弄个数据库呢? 文件保存数据有以下几个缺点࿱…...
voc数据集格式与yolo数据集格式的区别及相互转化
Pascal VOC数据集是目标检测领域最常用的标准数据集之一,几乎所有检测方向的论文都会给出其在VOC数据集上训练并评测的效果。VOC数据集包含的信息非常全,它不仅被拿来做目标检测,也可以拿来做分割等任务,因此除了目标检测所需的文…...
超详细!Android Termux上如何安装MySQL,内网穿透实现公网远程访问
文章目录 前言1.安装MariaDB2.安装cpolar内网穿透工具3. 创建安全隧道映射mysql4. 公网远程连接5. 固定远程连接地址 前言 Android作为移动设备,尽管最初并非设计为服务器,但是随着技术的进步我们可以将Android配置为生产力工具,变成一个随身…...
TSNE降维学习
在学习使用Cora数据集时,输入的初始为[2708, 1433], 输入一共有2708个点,每个节点有1433个特征。测试集的大小为[1000, 1433]最后的输出为[1000, 7],表示每个点的类别。 我们要的就是查看这个[1000, 7]的预测结果。想要将他展示在一个平面上是…...
基于Python+Selenium的web自动化测试框架详解
简介 随着Web应用程序的广泛应用和不断发展,Web自动化测试已经成为软件质量保证中的一个重要环节。而PythonSelenium作为一组强大的工具和框架,已经成为Web自动化测试领域中的热门技术之一。PythonSelenium可以帮助我们快速、准确地模拟用户行为和操作&…...
C (1094) : DS双向链表—前驱后继
Description 在双向链表中,A有一个指针指向了后继节点B,同时,B又有一个指向前驱节点A的指针。这样不仅能从链表头节点的位置遍历整个链表所有节点,也能从链表尾节点开始遍历所有节点。 对于给定的一列数据,按照给定的…...
mp4视频太大怎么压缩变小?
mp4视频太大怎么压缩变小?确实,很多培训和教学都转向了线上模式,这使得我们需要下载或分享大量的在线教学视频。然而,由于MP4视频文件通常较大,可能会遇到无法打开或发送的问题。为了解决这个问题,我们可以…...
利用easy excel 实现文件导出
一.创建实体类 package com.siact.product.jwp.module.report.dto;import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentRowHeight; import com.alib…...
LongLoRA:超长上下文,大语言模型高效微调方法
麻省理工学院和香港中文大学联合发布了LongLoRA,这是一种全新的微调方法,可以增强大语言模型的上下文能力,而无需消耗大量算力资源。 通常,想增加大语言模型的上下文处理能力,需要更多的算力支持。例如,将…...
【漏洞复现】某 NVR 视频存储管理设备远程命令执行
漏洞描述 NUUO NVR是中国台湾NUUO公司旗下的一款网络视频记录器,该设备存在远程命令执行漏洞,攻击者可利用该漏洞执行任意命令,进而获取服务器的权限。 免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律&am…...
若依前端-应用路径发布和使用
官网的路径:前端手册 | RuoYi 应用路径 有些特殊情况需要部署到子路径下,例如:https://www.ruoyi.vip/admin,可以按照下面流程修改。 1、修改vue.config.js中的publicPath属性 publicPath: process.env.NODE_ENV "produ…...
Mojo 正式发布,Rust 能否与之匹敌?
9 月 7 日,Modular 公司宣布正式发布 Mojo:Mojo 现在已经开放本地下载——初步登陆 Linux 系统,并将很快提供 Mac 与 Windows 版本。据介绍,Mojo 最初的目标是比 Python 快 35000 倍,近日该团队表示,Mojo 将…...
opencv实现抠图,图像拼接,图像融合
在OpenCV中,你可以使用图像拼接、抠图和将图像的一部分放在另一张图片的指定位置。以下是示例代码,演示如何执行这些操作: 图像拼接 要将两张图像拼接在一起,你可以使用 cv::hconcat(水平拼接)和 cv::vco…...
照片处理软件Lightroom Classic mac中文版功能介绍(Lrc2021)
Lightroom Classic 2022 mac是一款桌面编辑工具,lrc2021 mac包括提亮颜色、使灰暗的摄影更加生动、删除瑕疵、将弯曲的画面拉直等。您可以在电脑桌面上轻松整理所有照片。使用Lightroom Classic, 轻松整理编辑照片,为您的作品锦上添花。 Ligh…...
asp.net高校留学生信息管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio
一、源码特点 asp.net 高校留学生信息管理系统 是一套完善的web设计管理系统,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010,数据库为sqlserver2008,使 用c#语言开发 asp.net留学生信息管理系…...
C# - Opencv应用(1) 之VS下环境配置详解
C# - Opencv应用(1) 之VS下环境配置详解 有时候,单纯c#做前端时会联合C实现的dll来落地某些功能由于有时候会用C - Opencv实现算法后封装成dll,但是有时候会感觉麻烦,不如直接通过C#直接调用Opencv在此慢慢总结下C# -…...
rsync 远程同步实现快速、安全、高效的异地备份
目录 1 rsync 远程同步 1.1 rsync是什么? 1.2 rsync同步方式 1.3 rsync的特性 1.4 rsync的应用场景 1.5 rsync与cp、scp对比 1.6 rsync同步源 2 配置rsync源服务器 2.1 建立/etc/rsyncd.conf 配置文件 3 发起端 4 发起端配置 rsyncinotify 4.1 修改rsync…...
医学访问学者面试技巧
医学访问学者面试是一个非常重要的环节,它决定了你是否能够获得这个宝贵的机会去国外的大学或研究机构学习和研究。在这篇文章中,知识人网小编将分享一些关于医学访问学者面试的技巧,帮助你在面试中表现出色。 1. 准备充分 在参加医学访问学…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...
