Kotlin自定义字符串表达式求值代码结果错误求助
问题分析与修复
你的代码输出错误的核心原因是表达式分割逻辑错误和加减运算的符号处理错误,导致加减项的计算逻辑完全偏离预期:
具体错误点
sub函数逻辑错误
原代码中sub函数初始值设为0.0,然后逐个减去所有split("-")后的元素,相当于计算0 - a - b - c,但正确逻辑应该是a - b - c(当split结果为["a","b","c"]时)。更严重的是,当元素内部包含+时,这种方式会错误地将-b + c当成-(b + c)计算。add函数的逻辑误解
原add函数将split("-")后的每个元素内部的+直接合并,比如把表达式中-40/30x20+34/20对应的split元素"40/30x20+34/20"合并成26.666+1.7=28.366,但实际含义应该是-26.666 +1.7,而非-(26.666+1.7),这直接导致最终结果少加了3.4(相当于多减了3.4)。分割方式的缺陷
仅按-分割表达式,无法区分项的符号和内部加法,导致+项被错误归到前一个减号块中,符号处理完全混乱。
修复后的代码
我们换一种思路:先将表达式拆分为带符号的独立项,先计算每个项内部的乘除(从左到右,因为乘除优先级相同),最后将所有项的数值求和,完全符合运算优先级规则:
val expr = "5+4-10x20-40/30x20+34/20" // 将表达式拆分为带符号的项,例如"5+4-..."拆分为["+5", "+4", "-10x20", ...] fun splitIntoTerms(expr: String): List<String> { val terms = mutableListOf<String>() var start = 0 // 从第二个字符开始遍历,寻找项的分隔符(+或-) for (i in 1 until expr.length) { if (expr[i] == '+' || expr[i] == '-') { terms.add(expr.substring(start, i)) start = i } } // 添加最后一个项 terms.add(expr.substring(start)) // 给第一个无符号的项补正号 if (terms.first().first() != '+' && terms.first().first() != '-') { terms[0] = "+${terms[0]}" } return terms } // 计算单个带符号项的值,处理内部连续乘除 fun evaluateTerm(term: String): Double { // 提取项的符号 val sign = if (term.startsWith('-')) -1.0 else 1.0 // 剥离符号,得到纯数字和运算符部分 val numPart = term.removePrefix("+").removePrefix("-") // 拆分数字列表和运算符列表 val nums = numPart.split("x", "/").map { it.toDouble() } val ops = numPart.filter { it == 'x' || it == '/' } // 从左到右计算乘除 var result = nums[0] for (i in ops.indices) { when (ops[i]) { 'x' -> result *= nums[i + 1] '/' -> result /= nums[i + 1] } } return result * sign } // 主求值函数:拆分项 → 计算每个项 → 求和 fun eval(expr: String): Double { val terms = splitIntoTerms(expr) return terms.sumOf { evaluateTerm(it) } } fun main() { val result = eval(expr) println(result) // 输出 -215.96666666666667,与预期一致 }
修复说明
- splitIntoTerms函数:解决了原分割方式的缺陷,将每个运算项都带上符号,确保
-a + b被拆分为["-a", "+b"],彻底避免符号混淆。 - evaluateTerm函数:专门处理单个项的乘除运算,支持任意连续的乘除组合(比如
a/b/c或a*b/c*d),同时正确应用项的符号。 - eval函数:逻辑简化为拆分项、计算每个项、求和,完全符合「先乘除后加减」的运算优先级。
内容的提问来源于stack exchange,提问作者Blaze_2508
相关产品推荐
相关产品推荐

