首页 > 代码库 > 用Objective-C的foundation框架解决表达式求值问题
用Objective-C的foundation框架解决表达式求值问题
主要思想:
本程序分2个类
一个是ExpressionString类,主要用于存储表达式以及对它进行求值。以下是该类中的内容:
(NSString *)expString//用于存储要计算的表达式;
-(NSString*)caculateExpression//就用于计算该表达式的值。
另外一个类是ExpressionEvaluation,此类用于辅助ExpressionString类来对表达式进行求值。以下是该类中的内容:
-(id) init; //初始化函数
-(BOOL) isDigital; //判断是否是数字
-(NSString*) precede:(NSString*) a; //判断当前操作符和栈顶操作符的优先级
-(double) compute: (NSString*) opnt anOtherStr: (NSString*) a; //出栈计算
在main函数中,只需要3步就行了。定义、发送赋值消息、输出结果。3个步骤如下:
ExpressionString *es = [ExpressionString alloc];
[es setExpString:@"10÷6×7+15-8"];
//[es setExpString:@"10÷÷6×7+15-8"]; 此步骤是用于检查错误的测试用例,当使用这步时,系统会输出错误提示信息。
//[es setExpString:@"1000÷2"]; 此步骤用于检测整除之后输出整型,而不是浮点型的值。
NSLog(@"%@",[es caculateExpression]);
具体代码如下:共5个文件。
1 // 2 // ExpressionString.h 3 // exp1_2 4 // 5 // Created by junz on 12/27/14. 6 // Copyright (c) 2014 Caspar. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h>10 11 @interface ExpressionString : NSObject12 @property NSString *expString;13 - (NSString*)caculateExpression; 14 @end
1 // 2 // ExpressionString.m 3 // exp1_2 4 // 5 // Created by junz on 12/27/14. 6 // Copyright (c) 2014 Caspar. All rights reserved. 7 // 8 9 #import "ExpressionString.h" 10 #import "ExpressionEvaluation.h" 11 @implementation ExpressionString 12 @synthesize expString; 13 - (NSString*)caculateExpression 14 { 15 NSMutableArray *array = [[NSMutableArray alloc] init]; 16 for (int i = 0; i < [self.expString length]; i++)//初始化构造数组array存放所有字符 17 { 18 NSMutableString *s = [[NSMutableString alloc] init]; 19 s = [NSMutableString stringWithString: [self.expString substringWithRange:NSMakeRange(i, 1)]]; 20 if ([s isEqualToString:@"÷"]) s = [NSMutableString stringWithString: @"/"]; 21 else if ([s isEqualToString:@"×"]) s = [NSMutableString stringWithString: @"*"]; 22 else ; 23 array[i] = s; 24 } 25 array[[array count]] = @"#";//在array数组的末尾加上#作判断符用 26 //初始化2个栈,OPTR存放操作符,OPND存放操作数 27 NSMutableArray *OPTR = [[NSMutableArray alloc] init]; 28 NSMutableArray *OPND = [[NSMutableArray alloc] init]; 29 ExpressionEvaluation *current = [ExpressionEvaluation alloc]; //设置一个遍历指针current,从0开始对表达式进行遍历 30 ExpressionEvaluation *next = [ExpressionEvaluation alloc]; 31 double sum = 0; //表达式中操作数的值 32 int i = 0, k = -1, j = -1;//i用来遍历表达式,k用来记录OPND的大小,j用来记录OPTR的大小 33 int breakflag = 1; 34 current.str = array[i]; 35 while (![current.str isEqualToString: @"#"])//表达式未遍历完,则不断循环遍历 36 { 37 while ([current isDigital]) //判断当前指针所指的字符是不是数字,如果是,则将数字存入OPND 38 { 39 sum = 10 * sum + ([[current str] intValue]); 40 if (i >= ([array count] - 1)) 41 { 42 break; 43 } 44 [current setStr: array[++i]]; 45 if (![current isDigital]) { 46 OPND[++k] = [NSString stringWithFormat:@"%f", sum]; 47 sum = 0; 48 } 49 } 50 NSInteger flag = 1; //当current指针指向操作符时,则需要与OPTR栈顶元素进行比较 51 double temp = 0; 52 if (i < ([array count] - 1)) {//判断表达式的正确性 53 [next setStr: array[i+1]]; 54 if (![next isDigital] && ((![current.str isEqualToString:@")"] && ![next.str isEqualToString:@"("]) || [current.str isEqualToString:@")"] && [next.str isEqualToString:@"("]) { //情况1:")(";情况2:"**"或者"//"等等 55 56 breakflag = 0; 57 break; 58 } 59 } 60 //如果OPTR栈为空,则将当前current所指的操作符进栈 61 if ((j == -1) && ![current.str isEqualToString:@"#"]) 62 { 63 OPTR[++j] = [current str]; 64 [current setStr: array[++i]]; 65 flag = 0; 66 } 67 //如果当前OPTR不为空,则将current所指的操作符与OPTR栈顶元素进行比较 68 while (flag && (j >= 0)) { 69 ExpressionEvaluation *aa = [ExpressionEvaluation alloc]; 70 ExpressionEvaluation *bb = [ExpressionEvaluation alloc]; 71 if ([current.str isEqualToString:@"#"] && (j == -1)) { 72 break; 73 } 74 switch ([[current precede:OPTR[j]] isEqualToString:@"<"]) 75 { 76 case true: //如果OPTR栈顶元素小于current所指的操作符,则current所指的操作符进栈 77 OPTR[++j] = [current str]; 78 [current setStr: array[++i]]; 79 flag = 0; 80 break; 81 case false: 82 switch ([[current precede:OPTR[j]] isEqualToString:@"="]) 83 { 84 case true: //如果OPTR栈顶元素等于current所指的操作符,则消去括号,并使current指向下一个字符 85 j = j - 1; 86 [current setStr: array[++i]]; 87 break; 88 case false: 89 switch ([[current precede:OPTR[j]] isEqualToString:@">"]) 90 { case true://如果OPTR栈顶元素大于current所指的操作符,出栈计算,将结果入OPND栈 91 aa.str = OPND[k--]; 92 bb.str = OPND[k--]; 93 temp = [bb compute: OPTR[j--] anOtherStr:aa.str]; 94 OPND[++k] = [NSString stringWithFormat:@"%f", temp]; 95 break; 96 case false: breakflag = 0;break; //判断优先权为0时候的情况 97 } 98 } 99 default: break;100 }101 if ((j == -1) && ![current.str isEqualTo:@"#"])//判断OPTR栈是否为空,为空则将current所指的操作符入栈102 {103 OPTR[++j] = [current str];104 [current setStr: array[++i]];105 flag = 0;106 }107 }108 }109 if (breakflag) {110 //以下代码主要是为了防止类似10/2=5.000000的问题,程序从后往前逐个删除0,使最终得到10/2=5。111 NSMutableString *ss = [NSMutableString stringWithString:OPND[0]];112 while ([[ss substringWithRange:NSMakeRange(ss.length-1, 1)] isEqualToString:@"0"]) {113 [ss deleteCharactersInRange:NSMakeRange(ss.length-1, 1)];114 }115 if ([[ss substringWithRange:NSMakeRange(ss.length-1, 1)] isEqualToString:@"."]) [ss deleteCharactersInRange:NSMakeRange(ss.length-1, 1)];116 return ss;117 }118 else return @"This is not a correct expression, can not evaluate";119 }120 @end
1 // 2 // ExpressionEvaluation.h 3 // exp1_2 4 // 5 // Created by junz on 12/27/14. 6 // Copyright (c) 2014 Caspar. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h>10 11 @interface ExpressionEvaluation : NSObject12 @property NSMutableString* str;13 14 -(id) init;15 -(BOOL) isDigital; //判断是否是数字16 -(NSString*) precede:(NSString*) a; //判断当前操作符和栈顶操作符的优先级17 -(double) compute: (NSString*) opnt anOtherStr: (NSString*) a; //出栈计算18 @end
1 // 2 // ExpressionEvaluation.m 3 // exp1_2 4 // 5 // Created by junz on 12/27/14. 6 // Copyright (c) 2014 Caspar. All rights reserved. 7 // 8 9 #import "ExpressionEvaluation.h"10 11 @implementation ExpressionEvaluation12 @synthesize str;13 14 -(id) init15 {16 self.str = [[NSMutableString alloc] init];17 return self;18 }19 -(BOOL) isDigital20 {21 if (([self.str isGreaterThanOrEqualTo:@"0"]) && ([self.str isLessThanOrEqualTo:@"9"])) {22 return YES;23 }24 else return NO;25 }26 -(NSString*) precede:(NSString*) a27 {28 NSInteger i = 0, j = 0;29 NSArray *priori = [[NSArray alloc] initWithObjects:30 [NSArray arrayWithObjects:@">",@">",@"<",@"<",@"<",@">",@">", nil],31 [NSArray arrayWithObjects:@">",@">",@"<",@"<",@"<",@">",@">", nil],32 [NSArray arrayWithObjects:@">",@">",@">",@">",@"<",@">",@">", nil],33 [NSArray arrayWithObjects:@">",@">",@">",@">",@"<",@">",@">", nil],34 [NSArray arrayWithObjects:@"<",@"<",@"<",@"<",@"<",@"=",@"0", nil],35 [NSArray arrayWithObjects:@">",@">",@">",@">",@"=",@"0",@">", nil],36 [NSArray arrayWithObjects:@"<",@"<",@"<",@"<",@"<",@"0",@"=", nil],37 nil];38 if ([a isEqualToString:@"+"]) i = 0;39 else if ([a isEqualToString:@"-"]) i = 1;40 else if ([a isEqualToString:@"*"]) i = 2;41 else if ([a isEqualToString:@"/"]) i = 3;42 else if ([a isEqualToString:@"("]) i = 4;43 else if ([a isEqualToString:@")"]) i = 5;44 else if ([a isEqualToString:@"#"]) i = 6;45 else ;46 47 if ([self.str isEqualToString:@"+"]) j = 0;48 else if ([self.str isEqualToString:@"-"]) j = 1;49 else if ([self.str isEqualToString:@"*"]) j = 2;50 else if ([self.str isEqualToString:@"/"]) j = 3;51 else if ([self.str isEqualToString:@"("]) j = 4;52 else if ([self.str isEqualToString:@")"]) j = 5;53 else if ([self.str isEqualToString:@"#"]) j = 6;54 else ;55 56 return priori[i][j];57 }58 -(double) compute: (NSString*)opnt anOtherStr: (NSString*)a59 {60 double sum = 0;61 if ([opnt isEqualToString:@"+"]) sum = [self.str doubleValue] + [a doubleValue];62 else if ([opnt isEqualToString:@"-"]) sum = [self.str doubleValue] - [a doubleValue];63 else if ([opnt isEqualToString:@"*"]) sum = [self.str doubleValue] * [a doubleValue];64 else if ([opnt isEqualToString:@"/"]) sum = [self.str doubleValue] / [a doubleValue];65 else ;66 return sum;67 }68 @end
1 // 2 // main.m 3 // exp1_2 4 // 5 // Created by junz on 12/27/14. 6 // Copyright (c) 2014 Caspar. All rights reserved. 7 // 8 9 #import "ExpressionString.h"10 #import "ExpressionEvaluation.h"11 12 int main(int argc, const char * argv[]) {13 @autoreleasepool {14 ExpressionString *es = [ExpressionString alloc];15 // [es setExpString:@"1000÷2"];16 // [es setExpString:@"10÷6×7+15-8"];17 // [es setExpString:@"10÷÷6×7+15-8"]; //属于错误情况218 [es setExpString:@"10÷(6+2)(7)+15-8"]; //属于错误情况119 NSLog(@"%@",[es caculateExpression]);20 }21 return 0;22 }
总结:此程序能求解正确表达式的值,但是容错性稍微差了些,比如在main函数中,发这样一条消息:[es setExpString:@"10÷(6+2)(+15-8"];程序直接奔溃,没有实现很好的容错。
解决方法:
需要针对ExpressionString类中的compute方法进行改进。
1、对OPND和OPTR数组取数据时,把取出来的数据在OPND和OPTR中删除;
2、在返回值时,通过判断OPND和OPTR的大小来进行,而不是直接返回OPND[0]。
由于时间问题,此改进的操作等有时间的时候再搞。现在先暂且放一放。
用Objective-C的foundation框架解决表达式求值问题