Java实现四则运算算法(附带正负号识别和识错等)——错误判别(上)

运算式错误判别

接下来要做的就是判断运算式是否正确,如果存在错误最好能够给出大致的错误类型。
 

基本思路

错误类型整理

首先判断可能出现错误的地方(即大致有哪几种错误类型),比较容易想到的大概就这些:

  • 除零:最容易想到的,除法运算中除数为0
  • 左右括号不匹配
  • 定义域错误:暂时没有这个问题,因为之后可能要加入次方运算,就会对定义域有一定要求,比如不能对负数开方等
  • 运算符左右两边只有一边有数字,或多个运算符连续
  • 一个数字中存在多个小数点
  • 不能识别的符号
  • 其他可能没有想到的错误。

大致就是这些问题,最后两个其实可以归于一条,即数字字符串内的内容无法被转换为数字。
运算符的问题要考虑到之后可能加入的次方运算的特殊性(次方一般是一边是数字,另一边是其他运算符)。乘除运算不能放在运算式开头,一个运算符之后不能紧跟乘除运算(某些加减号在上一篇中已经被作为正负号处理了)。
进行简单的整理后大致有:

异常名称简单解释引发原因(程序中的辨别方法)
除零异常除法运算中除数为0在进行除法运算前检查除数
定义域异常次方运算、幂运算中运算数超出定义域在进行次方运算、幂运算前检查操作数(暂时用不到)
运算符异常算式第一个乘除前没有数字或运算符后紧跟乘除号设置一个标记,初始为true,读取到数字时改为false,读取到运算符后变为true,当读取到乘除号时以此进行判断
数字异常算式中存在无法识别的符号,或数字中有多个小数点这个问题最终会引发数字字符串转化数字失败,因此只需要判断转化是否成功
左右括号不匹配算式中左括号数量和右括号数量不一致这个问题会导致有括号被当做运算符运算,所以可以在运算前判断运算符
不明原因异常最后结束时符号栈栈顶应当是开始符号,结果发现不是结束时判断符号栈栈顶元素,这个问题最可能是因为括号不匹配

 

准备工作(自定义异常)

先编写一个自定义异常类,供后续抛出异常使用,将异常的提示信息写死。

package exception;

public class FormulaException extends Exception {

	//除零异常
	private static FormulaException divideByZeroException = new FormulaException("除零异常:算式中某个除法运算的除数为0,请检查");
	//定义域异常
	private static FormulaException definitionDomainException = new FormulaException("定义域越界:请检查根号或次方运算等是否正确");
	//运算符异常,某个运算符后紧接着乘除号或运算式开头为乘除号
	private static FormulaException characterException = new FormulaException("运算符使用错误,请检查!");
	//运算式中存在无法识别的符号,或数字中存在多个小数点,最终导致数字字符串无法转化为数字
	private static FormulaException figureException = new FormulaException("运算式错误:存在无法识别的符号");
	//左右括号不匹配
	private static FormulaException bracketMismatchException = new FormulaException("左右括号不匹配"); 
	//不明原因的异常,最可能是因为左右括号不匹配
	private static FormulaException unKnowException = new FormulaException("运算式不明错误:可能是左右括号不匹配");
	
	/*无参构造函数*/
	private FormulaException(){
		super();
	}   
	
	//用详细信息指定一个异常
	private FormulaException(String message){
		super(message);
	}
	    
	
	//用指定的详细信息和原因构造一个新的异常
	private FormulaException(String message, Throwable cause){
		super(message,cause);
	}
	    
	//用指定原因构造一个新的异常
	private FormulaException(Throwable cause) {
		super(cause);
	}
	
	/**
	 * 除零异常
	 * @return 带有除零异常提示信息的对象
	 */
	public static FormulaException getDivideByZeroException()
	{
		return divideByZeroException;
	}
	    
	/**
	 * 定义域异常
	 * @return 带有定义域异常提示信息的对象
	 */
	public static FormulaException getDefinitionDomainException()
	{
		return definitionDomainException;
	}
	
	/**
	 * 运算符异常
	 * @return 带有运算符使用错误信息的对象
	 */
	public static FormulaException getCharacterException()
	{
		return characterException;
	}
	
	/**
	 * 数字异常
	 * @return 带有引发该异常原因的提示信息的对象
	 */
	public static FormulaException getFigureException()
	{
		return figureException;
	}
	
	/**
	 * 不明异常
	 * @return 带有异常提示信息的对象
	 */
	public static FormulaException getUnKnowException()
	{
		return unKnowException;
	}
	
	/**
	 * 括号匹配异常
	 * @return 带有括号匹配错误信息的对象
	 */
	public static FormulaException getBracketMismatchException()
	{
		return bracketMismatchException;
	}
	
}

其他要求

我们希望在运算式发现错误时,计算过程能够立刻停下来,不再继续向下读取,然后直接抛出异常。
解决方法为,每个操作方法的返回值都改为boolean,如果发现异常则返回false,操作正常返回true,每次读取字符后都进行一次判断,如果发现返回了false,则停止读取。
由于同一个异常被反复抛出有可能会导致抛出失败(系统会自动忽视它),所以只在主方法中抛出异常。
 
 

编码

准备工作做完了,异常的判别方法在上面也已经列出,接下来只要根据判别方法进行编码即可。首先先在Calculator类的成员变量中添加一个异常:

private FormulaException exception;								//异常

当运算发现异常时,将异常在主方法中抛出。
 

运算符异常

先在Calculator类的成员变量中定义一个标记

private boolean flag = true;									//标记,前一个符号是否为运算符,是则为true

然后当读取到数字时,将它改为false,读取到运算符时,将它改为true,在原代码中修改:
读取到运算符时,将它改为true:

/**
	 * @description 当前读取到的字符是运算符时进行的操作
	 * 				<br>
	 * 
	 * @param currentCharacter 当前读取到的字符
	 */
	private void doWhenCharIsOperator(char currentCharacter,char proCharacter)
	{
		//非(当前符号是加减号且正负号标记激活状态),即当前符号不是正负号
		if (!(getPriority(currentCharacter) == 1 && NPCanUse == true))
		{
			pushFigure(currentCharacter,proCharacter);		//尝试将数字字符串进栈数字栈(有些特殊情况不能进栈)
			operate(currentCharacter);			//尝试运算(有些情况当前字符不会参与运算)
			if (currentCharacter != ')')
				flag = true;
		}
		//当前符号是正负号,并且为符号时,正负号标记*-1
		else
			NP *= currentCharacter == '-' ? -1: 1; 
		//当读取到加减号或左括号,下一个加减号视为正负号,NP激活
		if (getPriority(currentCharacter) == 1 || getPriority(currentCharacter) == 3)
			NPCanUse = true;
	}

读取到数字时,将它改为false:

/**
	 * @description 当前读取到的字符不是运算符时进行的操作
	 * 				<br>
	 * 				说明读取到的字符是数字,将它接到数字字符串之后
	 * 				<br>
	 * 				由于下一个字符一定不会是正负号,所以激活标记睡眠
	 * 
	 * @param currentCharacter 当前读取到的字符
	 */
	private void doWhenCharIsNotOperator(char currentCharacter)
	{
		figureString.append(currentCharacter);
		flag = false;
		NPCanUse = false;		//NP标记休眠
	}

接下来就是异常判断了,在读取到运算符时,如果flag标记为true,就说明符号使用存在问题了。修改方法:

	/**
	 * @description 当前读取到的字符是运算符时进行的操作
	 * 				<br>
	 * 
	 * @param currentCharacter 当前读取到的字符
	 */
	private boolean doWhenCharIsOperator(char currentCharacter,char proCharacter)
	{
		//非(当前符号是加减号且正负号标记激活状态),即当前符号不是正负号
		if (!(getPriority(currentCharacter) == 1 && NPCanUse == true))
		{
			if (flag == true && currentCharacter != '(')		//运算符后不能紧跟除左括号外的运算符
			{
				exception = FormulaException.getCharacterException();
				return false;
			}
			pushFigure(currentCharacter,proCharacter);		//尝试将数字字符串进栈数字栈(有些特殊情况不能进栈)
			operate(currentCharacter);			//尝试运算(有些情况当前字符不会参与运算)
			if (currentCharacter != ')')		//除右括号外其他运算符右边均不能接乘除号
				flag = true;
		}
		//当前符号是正负号,并且为符号时,正负号标记*-1
		else
			NP *= currentCharacter == '-' ? -1: 1; 
		//当读取到加减号或左括号,下一个加减号视为正负号,NP激活
		if (getPriority(currentCharacter) == 1 || getPriority(currentCharacter) == 3)
			NPCanUse = true;
		return true;
	}

然后在主方法中调用这个方法的地方检测这个方法是否成功,如果失败则抛出异常,在原来的代码中修改:

	/**
	 * @description 计算运算式(主程序)
	 * 				<br>
	 * 				根据传入的代表算式的字符串计算结果并返回
	 * @param formula 代表算式的字符串
	 * @return 计算结果
	 */
	public float calculate(String formula) throws FormulaException
	{
		formula += "#";
		operator.push('#');
		for (int i = 0;i < formula.length();i ++)
		{
			//读取到非运算符(非数字符号)时进行的操作
			if (!isOperator(formula.charAt(i)))
				doWhenCharIsNotOperator(formula.charAt(i));
			//读取到非运算符(数字符号)时进行的操作
			else
			{
				if (!doWhenCharIsOperator(formula.charAt(i),formula.charAt(i - 1 > -1 ? i -1 : 0)))
				{
					throw exception;
				}
			}
		}
		if (getPriority(operator.pop()) != -4)
			//字符串读取完成,但是符号栈内仍然有运算符
			return 0;
		else
			return figure.pop();
	}

到这里,运算符使用异常的辨识代码就写完了,然后进行一下简单的测试:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
当然,真正测试不可能只测这么三个,多测些,经过各种测试 以后。。。没有发现bug,那应该,可能,大概率是没有问题了,吧。那这个运算符异常就算过掉了。
 
 
 
上一页
下一页

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值