iOS课程的做业,按老师的说法,“为了更好地理解Foundation”,因此没有用NSExpression,而是本身实现一个栈来完成表达式求值。html
提及表达式求值,首先想到严奶奶版的数据结构教材就有现成的算法,能够直接拿过来用嘛。git
OperandType EvaluateExpression(){ //算术表达式求值的算符优先算法,设OPTR和OPND分别为运算符合运算数栈 //OP为运算符集合 InitStack(OPTR); Push(OPTR,'#') InitStack(OPND); c = getchar(); while(c != '#' || GetTop(OPTR) != '#'){ if(!In(c, OP)){ Push(OPND, c); c = getchar(); }//不是运算符则进栈 else switch(Precede(GetTop(OPTR), c)){ case '<': //栈顶元素优先级低,栈外运算符入栈 Push(OPTR, c); c = getchar(); break; case '=': //脱括号并接收下一字符 Pop(OPTR,x); c = getchar(); break; case '>': //栈顶元素优先级高,出栈并将运算结果入栈 Pop(OPTR, theta); Pop(OPND, b); Pop(OPND, a);//出栈顺序:先b后a Push(OPND, Operate(a, theta, b);//计算式:a theta b break; }//switch }//while return GetTop(OPND); }//EvaluateExpression
分析这个算法,能够知道整理出首先要用OC实现一个栈,而后实现如下几个函数便可。objective-c
//判断输入的字符是运算符仍是操做数 -(BOOL)isOperator:(NSString *)ch; //判断输入的字符串中是否含有非法字符(除了数字和运算符以外) -(BOOL)isNumberic:(NSString *) ch; //比较栈外和栈内元素优先级 -(NSString *)comparePriority:(NSString *)inOptr outOptr:(NSString *)outOptr; //计算opnd1 optr opnd2 -(double)calculate:(double)opnd1 opnd2:(double)opnd2 optr:(NSString *)optr; //实现上述算法 -(NSString *)ExpressionCalculate:(NSString *)inputString;
数据存储
考虑到数据的动态变化,使用NSMutableArray来存放算法
初始化
直接用initWithCapacity:数组是空的,由于它只分配内存,得往里面塞点东西。express
pop函数
最开始使用的下面的函数定义:segmentfault
-(BOOL)pop:(NSString *)element stack:(Stack *)stack
而后发现element没办法传回去,好比,我调用:数组
NSString *a; pop:a stack:self.opnd //NSLog: a = null
因此修改了下,增长了一个property放pop出来的元素,而且赋上pop的返回值来调用数据结构
-(NSString *)pop:(Stack *)stack //调用 NSString *a; a = [self.opnd pop:self.opnd];
这就好啦。函数
使用字典NSDictionary,按栈内和栈外分两个字典存放优先级;this
优先级采用百度文库上定义的一个表;
两个优先级字典采用类方法初始化;
优先级比较的时候,用到NSString与NSInteger的转化
//NSInteger转化NSString类型: [NSString stringWithFormat: @"%d", NSInteger]; //NSString转化 NSInteger类型: NSInteger myInteger = [myString integerValue];
switch不能直接用NSString类型做为expression,在StackOverflow上搜索了一下解决办法,出于已经写的代码的考虑,采用第三个回答的方法试试。
用来输入字符;
使用view做为代理,完成在点击键盘外部时隐藏键盘
处理输入的字符串:
(1)对其进行分割,按数字和运算符分别存储在不一样的数组中。对于须要用到函数是componentsSeparatedByCharactersInSet和characterSetWithCharactersInString这两个神奇的组合。好比:
self.arrayToCalculate = [inputString componentsSeparatedByCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"+-*/%"]]; 只是有个问题,这样分割出来的数组中,会在原表达式出现括号的地方出现空白符,不是很理解。[?]
对于运算符,是对字符串进行逐个扫描,提取出+-*/等运算符号;若是采用提取数字的一样的方法,会出现(-这样,括号和运算符连在一块儿的状况,由于它们都在我给的运算符集合中,连在一块儿的时候天然不会分割。
关于[?]处的解答,在网上查了一下,是componentsSeparatedByCharactersInSet的问题。苹果的文档是这么描述的:
Adjacent occurrences of the separator characters produce empty strings in the result. Similarly, if the string begins or ends with separator characters, the first or last substring, respectively, is empty.
意思大概是,处理分割string的时候,若是连续出现了用于分割的字符集合set中的两个字符,或者恰好set中的字符处于string的开始或结尾的地方,就会出现空白。
StackOverflow上有人给了一个处理第二种状况的办法,即采用stringByTrimmingCharactersInSet函数,将开始和结尾处的set中的字符trim掉。
(2)为何要事先分割输入的字符串呢?
我是将输入的字符串按字符串index一个一个取出来的,运算符还好,但若是是两位数三位数就惨了。因此事先将要进行运算的操做数取出来,每次在扫描到下一个字符是运算符时,将arrayToCalculate中的第一个元素取出入栈,而后在arrayToCalculate中删除第一个元素。
//删除下标为0的(即第一个元素) [self.arrayToCalculate removeObjectAtIndex:0];
double与NSString的相互转换
double num = [NSString doubleValue]; NSString * str = [NSString stringWithFormat:@"%f", num];
NSArray与NSMutableArray的相互转换
//componentsSeparatedByCharactersInSet返回的是NSArray NSArray * tempArray = [inputString componentsSeparatedByCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"(+-*/%=)"]]; self.arrayToCalculate = [NSMutableArray arrayWithArray:tempArray];
char转换为NSString
//方式一:使用stringWithFormat char c = 'a'; NSString *s = [NSString stringWithFormat:@"%c", c]; //方式二:使用-stringWithUTF8String: char *ch = ……; NSString *str = [NSString stringWithUTF8String:&ch];
使用stringWithUTF8String:的话,str末尾会包含"\n",看个人问题就知道这是一个多么让人伤心的领悟。另外,也能够发现stringWithFormat:是个挺万金油的方法,好像能够把你们都变成NSString的样子。
使用for循环也可让当前元素停下来。
注意当栈顶元素的优先级高于栈外元素时,要将栈顶元素弹出,此时要注意保存当前的栈外元素。算法中用的while循环,很容易保存,不接受下一个元素就能够了;若是是for循环的话,每次循环必定会递增,因此若是要保存当前栈外元素的话,将i--就能够啦。
再次使用了NSCharacterSet这个类,用到了一个decimalDigitCharacterSet类方法,苹果文档里是这么说的:
Returns a character set containing the characters in the category of Decimal Numbers.
Informally, this set is the set of all characters used to represent the decimal values 0 through 9. These characters include, for example, the decimal digits of the Indic scripts and Arabic.
个人代码 将Digits打印出来是这样的:__NSCFCharacterSet: 0x7ffb4ad23b60,不太明白是什么玩意儿,心塞,回头再研究。