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,不太明白是什麼玩意兒,心塞,回頭再研究。