关于用java正则表达式检索简易数学表达式并计算结果

关于用java正则表达式检索简易数学表达式并计算结果

目标:通过设计一个简单的数学表达式计算器,要求设计者以面向对象程序的设计方式来实现计算器的具体功能。

程序规则:
(1)表达式定义
本程序表达式设定为可由多个运算符和数字组成,可以含括号,为了降低题目难度,括号只用于
标注数字为正数还是负数,同时,假设操作数是整数,运算符只有四种类型:+、-、和/,例如如下
表达式:-2+3
(-5)/3-29。
(2)有效表达式校验
在对表达式求值运算之前,必须先对表达式的正确性进行校验。例如:空字符串、运算符连续、 空括号、括号不配对、右括号前是运算符、“(”不为第一个字符且前面不是运算符、“)”不为最后
一个字符且后面不是运算符、表达式内含非法字符等。
(3)运算规则
为简单起见,如果表达式格式正确,表达式计算不考虑运算符的优先级,即加减乘除是相同优先
级,则从左到右依次计算,最终得出结果(例:1+3
6=24)。此外,除法运算遵从 C 语言中整数除法的运算规则(即取整),另外,一旦出现除零操作,程序要给出相应错误提示。

我的思路

<1.表达式正确性验证>

(1)对于这个任务要求输入的数学表达式的格式十分简单,只需检索是否满足"数字 运算符 数字 运算符…数字"的格式就可以判断其是否是一个正确的数学表达式。而仔细观察此格式就可以发现,除去第一个数字以外,后面都满足"运算符+数字"的格式,即后面可以是一个"运算符+数字"的重复出现,如果用正则表达式模拟的话应该是"数字[运算符 数字]*"的格式。

(2)对于运算符,此题给出了+ ,- ,** ,/ 四种符号,分别代表了加,减,乘,除四种数学上的基本运算形式。并且,此题的四种运算无优先顺序,而是直接从左向右依次计算结果。 尤其要注意的是,在用java的正则表达式检索运算符的时候,是一个含有特殊意义的字符,不能直接使用,需要用双斜杠"\\"来对*号进行转译。 如果要用正则表达式来模拟的话应该是"[+ - \\* /]"的格式。

(3)对于数字,本题设置了含有括号的负数的形式,即除在第一个位置的数字以外,其余地方如果要是有负数,则必须用 “(” 和 “)” 括起来,并且 “(” 和 “)” 之间只能有负数,不能有其他东西。
另外,对于一个合法的数字,其开头第一个数字不能为0(除数字0与-0以外),如果用正则表达式来模拟的话应该是"( [1-9]\\d* | \\(-[1-9]\d*\\) | 0 | \\(-0\\) )“的格式。 ( 注: 开头数字的正则表达式会比此正则表达式多出”-[1-9]\d*","-0"两种情况,只需要用"|"把他们加入到上面的正则表达式中即可)。

(4)综上,本题用于验证数学表达式正确性的正则表达式为:"(\\(-[1-9]\\d*\\) | -[1-9]\\d* | [1-9]\\d* | 0 | -0 | \\(-0\\)) ([+ - / \\* ] (\\(-[1-9]\\d\\) | [1-9]\\d* | \\(-0\\) | 0))*"。以下是图片:这是检验表达式的正则表达式截图
<2.计算表达式的值>

(1)拆分表达式
检验完数学表达式并且表达式正确之后,则需要对表达式进行拆分,提取出有效的数据以及运算符。为了把数字完整的提取出来,我使用了" .split("\\b") "的拆分方式(注:拆分字符串的方法多种多样,我使用这种方法的好处是不会把一个多位数拆分成多个数字,可以一步到位的把一个正整数完整的拆分下来,例如"1+2-(-33)/465".split("\\b")会被拆分成一个含有"1","+",“2”,(-",“33”,")/","465"的字符串数组)。

(2)处理拆分后只含有数字的字符串数组
将表达式拆分之后,会得到一个字符串数组。我们对其进行分类,将只含有数字的字符串强制类型转换为整数并存入一个整形动态数组num,即num.add(Integer.parseInt(s[i]))。然后再对剩下的字符串数组进行分析。

(3)处理剩下的字符串数组
观察剩下的字符串数组,在这个数学表达式正确的前提下,剩下的字符串数组长度只能在[1,4]之间。对长度进行分类再分析

①长度为1:如果某个字符串数组的长度为1,那只能是+,-,*,/,(,)之间的某一个,但有用的只有+,-,*,/,所以如果是+,-,*,/就将其强制类型转换为字符型并存入一个字符型动态数组operator,即operator.add(String.valueOf(ch[0]))。如果不是则用".replaceFirst()"的方法去掉。

②长度为2:如果某个字符串数组的长度为2,且满足"\\)[+ - / \\*]" 的格式,则有用的运算符为第二个字符,将此字符串的第二个字符存入动态数组operator,剩下的字符则用".replaceFirst()"的方法去掉。

③长度为3:如果某个字符串的长度是3,且满足"[+ - / \\*]\\(-“的格式,则有用的运算符为第一个字符,按上述方法对其进行处理。但由于这个字符串结尾是一个”-"号,一定代表负号的意思,则其下一个数字必须取反才能得到正确的结果。所以可以设置一个boolean类型的标记isminus,一旦遇到这个格式则设置其为true,然后让下一个数字取反。

④长度为4:如果某个字符串的长度为4,且满足 "\\)[+ - / \\*]\\(-“的格式,则有用的运算符为第二个运算符。按上述的方法对其进行处理,这个格式结尾也也”-"号,所以其处理方式同③。

4)进行计算
将数学表达式切割完成后,会得到数据动态数组和运算符动态数组,设置一个循环,循环条件为运算符动态数组是否为空while(operator.size() ! = 0)。然后每次从数据数组中拿出前两个数据,从运算符数组中拿出第一个运算符,对运算符进行判断并计算得到相应的值。然后将值插入到数据数组的第3个位置,再用".remove()"的方法把用过的数据和运算符全部从各自数组中删除,如此循环,直到运算符数组为空。此时数据数组中只剩下一个数据,那就是结果

你可能感兴趣的:(java)