用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个文件。
//
// ExpressionString.h
// exp1_2
//
// Created by junz on 12/27/14.
// Copyright (c) 2014 Caspar. All rights reserved.
// #import <Foundation/Foundation.h> @interface ExpressionString : NSObject
@property NSString *expString;
- (NSString*)caculateExpression;
@end
//
// ExpressionString.m
// exp1_2
//
// Created by junz on 12/27/14.
// Copyright (c) 2014 Caspar. All rights reserved.
// #import "ExpressionString.h"
#import "ExpressionEvaluation.h"
@implementation ExpressionString
@synthesize expString;
- (NSString*)caculateExpression
{
NSMutableArray *array = [[NSMutableArray alloc] init];
for (int i = ; i < [self.expString length]; i++)//初始化构造数组array存放所有字符
{
NSMutableString *s = [[NSMutableString alloc] init];
s = [NSMutableString stringWithString: [self.expString substringWithRange:NSMakeRange(i, )]];
if ([s isEqualToString:@"÷"]) s = [NSMutableString stringWithString: @"/"];
else if ([s isEqualToString:@"×"]) s = [NSMutableString stringWithString: @"*"];
else ;
array[i] = s;
}
array[[array count]] = @"#";//在array数组的末尾加上#作判断符用
//初始化2个栈,OPTR存放操作符,OPND存放操作数
NSMutableArray *OPTR = [[NSMutableArray alloc] init];
NSMutableArray *OPND = [[NSMutableArray alloc] init];
ExpressionEvaluation *current = [ExpressionEvaluation alloc]; //设置一个遍历指针current,从0开始对表达式进行遍历
ExpressionEvaluation *next = [ExpressionEvaluation alloc];
double sum = ; //表达式中操作数的值
int i = , k = -, j = -;//i用来遍历表达式,k用来记录OPND的大小,j用来记录OPTR的大小
int breakflag = ;
current.str = array[i];
while (![current.str isEqualToString: @"#"])//表达式未遍历完,则不断循环遍历
{
while ([current isDigital]) //判断当前指针所指的字符是不是数字,如果是,则将数字存入OPND
{
sum = * sum + ([[current str] intValue]);
if (i >= ([array count] - ))
{
break;
}
[current setStr: array[++i]];
if (![current isDigital]) {
OPND[++k] = [NSString stringWithFormat:@"%f", sum];
sum = ;
}
}
NSInteger flag = ; //当current指针指向操作符时,则需要与OPTR栈顶元素进行比较
double temp = ;
if (i < ([array count] - )) {//判断表达式的正确性
[next setStr: array[i+]];
if (![next isDigital] && ((![current.str isEqualToString:@")"] && ![next.str isEqualToString:@"("]) || [current.str isEqualToString:@")"] && [next.str isEqualToString:@"("]) { //情况1:")(";情况2:"**"或者"//"等等 breakflag = ;
break;
}
}
//如果OPTR栈为空,则将当前current所指的操作符进栈
if ((j == -) && ![current.str isEqualToString:@"#"])
{
OPTR[++j] = [current str];
[current setStr: array[++i]];
flag = ;
}
//如果当前OPTR不为空,则将current所指的操作符与OPTR栈顶元素进行比较
while (flag && (j >= )) {
ExpressionEvaluation *aa = [ExpressionEvaluation alloc];
ExpressionEvaluation *bb = [ExpressionEvaluation alloc];
if ([current.str isEqualToString:@"#"] && (j == -)) {
break;
}
switch ([[current precede:OPTR[j]] isEqualToString:@"<"])
{
case true: //如果OPTR栈顶元素小于current所指的操作符,则current所指的操作符进栈
OPTR[++j] = [current str];
[current setStr: array[++i]];
flag = ;
break;
case false:
switch ([[current precede:OPTR[j]] isEqualToString:@"="])
{
case true: //如果OPTR栈顶元素等于current所指的操作符,则消去括号,并使current指向下一个字符
j = j - ;
[current setStr: array[++i]];
break;
case false:
switch ([[current precede:OPTR[j]] isEqualToString:@">"])
{ case true://如果OPTR栈顶元素大于current所指的操作符,出栈计算,将结果入OPND栈
aa.str = OPND[k--];
bb.str = OPND[k--];
temp = [bb compute: OPTR[j--] anOtherStr:aa.str];
OPND[++k] = [NSString stringWithFormat:@"%f", temp];
break;
case false: breakflag = ;break; //判断优先权为0时候的情况
}
}
default: break;
}
if ((j == -) && ![current.str isEqualTo:@"#"])//判断OPTR栈是否为空,为空则将current所指的操作符入栈
{
OPTR[++j] = [current str];
[current setStr: array[++i]];
flag = ;
}
}
}
if (breakflag) {
//以下代码主要是为了防止类似10/2=5.000000的问题,程序从后往前逐个删除0,使最终得到10/2=5。
NSMutableString *ss = [NSMutableString stringWithString:OPND[]];
while ([[ss substringWithRange:NSMakeRange(ss.length-, )] isEqualToString:@""]) {
[ss deleteCharactersInRange:NSMakeRange(ss.length-, )];
}
if ([[ss substringWithRange:NSMakeRange(ss.length-, )] isEqualToString:@"."]) [ss deleteCharactersInRange:NSMakeRange(ss.length-, )];
return ss;
}
else return @"This is not a correct expression, can not evaluate";
}
@end
//
// ExpressionEvaluation.h
// exp1_2
//
// Created by junz on 12/27/14.
// Copyright (c) 2014 Caspar. All rights reserved.
// #import <Foundation/Foundation.h> @interface ExpressionEvaluation : NSObject
@property NSMutableString* str; -(id) init;
-(BOOL) isDigital; //判断是否是数字
-(NSString*) precede:(NSString*) a; //判断当前操作符和栈顶操作符的优先级
-(double) compute: (NSString*) opnt anOtherStr: (NSString*) a; //出栈计算
@end
//
// ExpressionEvaluation.m
// exp1_2
//
// Created by junz on 12/27/14.
// Copyright (c) 2014 Caspar. All rights reserved.
// #import "ExpressionEvaluation.h" @implementation ExpressionEvaluation
@synthesize str; -(id) init
{
self.str = [[NSMutableString alloc] init];
return self;
}
-(BOOL) isDigital
{
if (([self.str isGreaterThanOrEqualTo:@""]) && ([self.str isLessThanOrEqualTo:@""])) {
return YES;
}
else return NO;
}
-(NSString*) precede:(NSString*) a
{
NSInteger i = , j = ;
NSArray *priori = [[NSArray alloc] initWithObjects:
[NSArray arrayWithObjects:@">",@">",@"<",@"<",@"<",@">",@">", nil],
[NSArray arrayWithObjects:@">",@">",@"<",@"<",@"<",@">",@">", nil],
[NSArray arrayWithObjects:@">",@">",@">",@">",@"<",@">",@">", nil],
[NSArray arrayWithObjects:@">",@">",@">",@">",@"<",@">",@">", nil],
[NSArray arrayWithObjects:@"<",@"<",@"<",@"<",@"<",@"=",@"", nil],
[NSArray arrayWithObjects:@">",@">",@">",@">",@"=",@"",@">", nil],
[NSArray arrayWithObjects:@"<",@"<",@"<",@"<",@"<",@"",@"=", nil],
nil];
if ([a isEqualToString:@"+"]) i = ;
else if ([a isEqualToString:@"-"]) i = ;
else if ([a isEqualToString:@"*"]) i = ;
else if ([a isEqualToString:@"/"]) i = ;
else if ([a isEqualToString:@"("]) i = ;
else if ([a isEqualToString:@")"]) i = ;
else if ([a isEqualToString:@"#"]) i = ;
else ; if ([self.str isEqualToString:@"+"]) j = ;
else if ([self.str isEqualToString:@"-"]) j = ;
else if ([self.str isEqualToString:@"*"]) j = ;
else if ([self.str isEqualToString:@"/"]) j = ;
else if ([self.str isEqualToString:@"("]) j = ;
else if ([self.str isEqualToString:@")"]) j = ;
else if ([self.str isEqualToString:@"#"]) j = ;
else ; return priori[i][j];
}
-(double) compute: (NSString*)opnt anOtherStr: (NSString*)a
{
double sum = ;
if ([opnt isEqualToString:@"+"]) sum = [self.str doubleValue] + [a doubleValue];
else if ([opnt isEqualToString:@"-"]) sum = [self.str doubleValue] - [a doubleValue];
else if ([opnt isEqualToString:@"*"]) sum = [self.str doubleValue] * [a doubleValue];
else if ([opnt isEqualToString:@"/"]) sum = [self.str doubleValue] / [a doubleValue];
else ;
return sum;
}
@end
//
// main.m
// exp1_2
//
// Created by junz on 12/27/14.
// Copyright (c) 2014 Caspar. All rights reserved.
// #import "ExpressionString.h"
#import "ExpressionEvaluation.h" int main(int argc, const char * argv[]) {
@autoreleasepool {
ExpressionString *es = [ExpressionString alloc];
// [es setExpString:@"1000÷2"];
// [es setExpString:@"10÷6×7+15-8"];
// [es setExpString:@"10÷÷6×7+15-8"]; //属于错误情况2
[es setExpString:@"10÷(6+2)(7)+15-8"]; //属于错误情况1
NSLog(@"%@",[es caculateExpression]);
}
return ;
}
总结:此程序能求解正确表达式的值,但是容错性稍微差了些,比如在main函数中,发这样一条消息:[es setExpString:@"10÷(6+2)(+15-8"];程序直接奔溃,没有实现很好的容错。
解决方法:
需要针对ExpressionString类中的compute方法进行改进。
1、对OPND和OPTR数组取数据时,把取出来的数据在OPND和OPTR中删除;
2、在返回值时,通过判断OPND和OPTR的大小来进行,而不是直接返回OPND[0]。
由于时间问题,此改进的操作等有时间的时候再搞。现在先暂且放一放。
用Objective-C的foundation框架解决表达式求值问题的更多相关文章
- java实现算术表达式求值
需要根据配置的表达式(例如:5+12*(3+5)/7.0)计算出相应的结果,因此使用java中的栈利用后缀表达式的方式实现该工具类. 后缀表达式就是将操作符放在操作数的后面展示的方式,例如:3+2 后 ...
- 刁肥宅详解中缀表达式求值问题:C++实现顺序/链栈解决
1. 表达式的种类 如何将表达式翻译成能够正确求值的指令序列,是语言处理程序要解决的基本问题,作为栈的应用事例,下面介绍表达式的求值过程. 任何一个表达式都是由操作数(亦称运算对象).操作符(亦称运算 ...
- Aviator 表达式求值引擎开源框架
简介¶ Aviator是一个高性能.轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值.现在已经有很多开源可用的java表达式求值引擎,为什么还需要Avaitor呢? Aviato ...
- 【算法】E.W.Dijkstra算术表达式求值
算术表达式求值 我们要学习的一个栈的用例同时也是展示泛型的应用的一个经典例子,就是用来计算算术表达式的值,例如 ( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) ) 如果将4乘以5,把3 ...
- lintcode 中等题:Evaluate Reverse Polish notation逆波兰表达式求值
题目 逆波兰表达式求值 在逆波兰表达法中,其有效的运算符号包括 +, -, *, / .每个运算对象可以是整数,也可以是另一个逆波兰计数表达. 样例 ["2", "1&q ...
- nyist0j 35 表达式求值
题目链接:表达式求值 该题以前做过但是WA了,今天终于把他解决了,各种悲剧啊,又是考虑不周到啊................... 所以贴出来纪念一下,并作为一个警示 /**** ps:注意当遇到 ...
- 函数嵌套 lisp表达式求值
问题 D: lisp表达式求值 时间限制: 1 Sec 内存限制: 128 MB提交: 105 解决: 43[提交][状态][讨论版] 题目描述 lisp是一种非常古老的计算机语言,是由约翰·麦卡 ...
- 第四届河南省ACM 表达式求值 栈
表达式求值 时间限制: 1 Sec 内存限制: 128 MB 提交: 14 解决: 7 [提交][状态][讨论版] 题目描述 Dr.Kong设计的机器人卡多掌握了加减法运算以后,最近又学会了一些简 ...
- C++之字符串表达式求值
关于字符串表达式求值,应该是程序猿们机试或者面试时候常见问题之一,昨天参加国内某IT的机试,压轴便为此题,今天抽空对其进行了研究. 算术表达式中最常见的表示法形式有 中缀.前缀和 后缀表示法.中缀表示 ...
随机推荐
- 关于cshtml中的js对动态编译支持的问题
问题:MVC4中支持对ViewBag.ViewDate等的动态编译,但是在js中对它的支持就是有问题.虽然是可以动态编译,但是动态编译之后,断点无法获取. $.getJSON("/api/A ...
- 汉语转拼音pinyin4j
分享一个将汉语转成拼音的工具包:pinyin4j-2.5.0.jar,下载地址:http://download.csdn.net/detail/abc_key/7629141 使用例如以下代码 imp ...
- 【美妙的Python之中的一个】Python简单介绍及环境搭建
美妙的Python之Python简单介绍及安装 简而言之: Python 是能你无限惊喜的语言,与众不同. 1.Python: ...
- 从零开始学android开发-详细谈谈intent的startActivityForResult()方法
1.两种实现activity跳转的方法 实现activity的跳转主要有两种方法,startActivity()和startActivityForResult();例如activity A跳转到act ...
- HttpClient 4.3.* 上传带中文文件名文件文件名乱码问题的解决
又是折腾了一天才解决的问题,网上关于这个问题的资料不多,希望写出来能帮到有需要的人. 之前无论怎么设置charset都不起作用, 后来看了这篇文章 才发现MultipartEntityBuilder有 ...
- MVC - 学习总目录
MVC - 基础 MVC - HtmlHelper类 MVC - 路由 MVC - 身份验证 MVC - 模型验证 MVC - Ajax MVC - 布局
- MySQL之事务隔离级别--转载
转自:http://793404905.blog.51cto.com/6179428/1615550 本文通过实例展示MySQL事务的四种隔离级别. 1 概念阐述 1)Read Uncommitted ...
- C++ (P103—P154)
1 任一指针变量本身的数据值得类型都是unsigned long int 2 指针值为0的叫做空指针,为了安全起见,声明指针时最好初始化,哪怕是初始化为空指针 3 一般不能使用不同类型变量的地址来给指 ...
- posix thread概述
1. 基本概念 一个Unix进程可以理解为一个线程加上地址空间.文件描述符和其他数据.异步表明事情相互独立发生, 除非有强加的依赖性. 并发指实际可能是穿行发生的事情好像同时发生一样.并行指并发序列同 ...
- 世界上最方便的SharePoint移动客户端--Rshare
Rshare我试用了一段时间,同时也测试了其他家产品,使用后的感觉是Rshare无愧于世界上最方面的SharePoint移动客户端. 1.界面设计很方便,设计中充分考虑到移动客户的使用习惯及喜好,设计 ...