首页 > 代码库 > 用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框架解决表达式求值问题