此计算器解析错误的解决方法

时间:2018-06-15 06:48:58

标签: java parsing calculator string-parsing

背景:

我将表达式3.24 * 10^10 + 1输入到我制作的计算器中。 我的计算器解决此问题的方法是 - 它首先查找模式number_a^number_b,使用Double.parseDouble()方法将2个数字解析为double,然后执行Math.pow(number_a, number_b)并将表达式替换为结果

然后,计算器同样寻找模式number_a * number_b并解析它。到目前为止,我们的表达式变为3.24E10 + 1。现在是棘手的部分。当我编写这个计算器时,我考虑到计算器应该找到模式number_a + number_b并解析它。我的计算器确实做到了这一点,并且意外但又合理地返回结果 - 3.24E11.0

我正在寻找解决方法,让我的计算器足够智能,以处理这些表达。

重要信息 - 正则表达式示例= ([\\d\\.]+)\\*([\\d\\.]+)

代码示例 -

// here 'expression' is a StringBuilder type
// only a (modified) snippet of actual code.

Matcher m = Pattern.compile ("([\\d\\.]+)\\^([\\d\\.]+)")
                           .matcher (expression.toString());
while (m.find()) {
     Double d1 = Double.parseDouble(m.group(1));
     Double d2 = Double.parseDouble(m.group(2));
     Double d3 = Math.pow(d1, d2);
     expression.replace(m.start(), m.end(), Double.toString(d3));
     m.reset(expression);
}

PS :根据我提出问题的方式,很多人似乎认为我的计算器尝试失败,因为正则表达式不会让我走得太远。当然,我同意这是真的,并且可能存在更好的算法。我只想说清楚: -

1)正则表达式仅用于以直接形式解析表达式。我没有使用正则表达式。使用递归解决嵌套括号。只有在完成所有处理工作并且剩下的只是简单的计算时,正则表达式才会在最后一步发挥作用。

2)我的计算器工作正常。它可以并且确实可以优雅地解决嵌套表达式。证明 - 2^3*2/4+1 --> 5.0sin(cos(1.57) + tan(cos(1.57)) + 1.57) --> 0.9999996829318346((3(2log(10))+1)+1)exp(0) --> 8.0

3)不要使用过多的拐杖'。如果您认为我已经编写了数千行代码来获得所需的功能。排名第200,这就是它。而且我无意倾销我的申请(即将完成)。

2 个答案:

答案 0 :(得分:2)

  

如果你能为我提供正则表达式不合适的理由

  1. 真正的正则表达式无法正确解析嵌套/平衡括号。 (好的,可以使用高级正则表达式功能来完成它,但结果很难理解 1 。)

  2. 真正的正则表达式将难以分析具有不同优先级的运算符的表达式。特别是带支架。 (我不确定这是不可能的,但肯定很难。)

  3. 一旦你使用你的正则表达式来匹配表达式,你就会遇到将你匹配的“组”整理成允许你(正确)评估表达式的问题。 / p>

  4. 如果输入在语法上无效,则正则表达式不能产生任何解释。

  5. 复杂的正则表达式通常在路径上很昂贵......特别是对于不正确的大输入字符串。

  6.   

    其他算法到底能做些什么才能使它们更胜一筹。

    正确编写或生成的词法分析器+解析将不会出现上述问题。您可以动态评估表达式,也可以将其转换为可以重复计算的解析树;例如具有不同的变量值。

    分流码算法(虽然应用较为有限)也没有上述问题。

    这是为工作挑选合适的工具。而且还要认识到正则表达式不适合每项工作。

    1 - 如果你想探索使用正则表达式解析嵌套结构的兔子,here是一个入口。

答案 1 :(得分:1)

根据你的评论,改变正则表达式:

([\\d\\.]+)\\*([\\d\\.]+)

这项工作:

(\\d+(\\.\\d+)?(e\\d+)?)\\^(\\d+(\\.\\d+)?(e\\d+)?)

解释我所改变的内容:之前,您可以按以下格式输入数字:

  1. 1
  2. .5
  3. .......
  4. .3.76
  5. 为了克服这个问题:我添加了一个可选的小数位((\\.\\d+)?),它允许整数,但也包含小数。

    另外,通过在两侧添加可选的科学记数法((e\\d+)?),允许写入数字:

    1. 作为整数(2 ^ 5
    2. 小数(2.3 ^ 5.7
    3. 和科学(2.345e2 ^ 5e10
    4. 一样

      您当然可以混合所有变体。

      但请记住您问题下方的评论。正则表达式对于小位可能是有用的,但它可以变得非常结块,缓慢和混乱,方程式越大。

      此外,如果您想支持负数,您可以在基数和指数前添加可选连字符:

      (-?\\d+(\\.\\d+)?(e-?\\d+)?)\\^(-?\\d+(\\.\\d+)?(e-?\\d+)?)
      
相关问题