前言
前两周举行了计算器的仿写,运用了刚学习的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;
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |