用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 : NSObject
12 @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 : NSObject
12 @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 ExpressionEvaluation
12 @synthesize str;
13 
14 -(id) init
15 {
16     self.str = [[NSMutableString alloc] init];
17     return self;
18 }
19 -(BOOL) isDigital
20 {
21     if (([self.str isGreaterThanOrEqualTo:@"0"]) && ([self.str isLessThanOrEqualTo:@"9"])) {
22         return YES;
23     }
24     else return NO;
25 }
26 -(NSString*) precede:(NSString*) a
27 {
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*)a
59 {
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"];  //属于错误情况2
18         [es setExpString:@"10÷(6+2)(7)+15-8"]; //属于错误情况1
19         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]。

由于时间问题,此改进的操作等有时间的时候再搞。现在先暂且放一放。

posted @ 2014-12-30 10:51  CasparJ  阅读(295)  评论(0编辑  收藏  举报