如何在Jetpack Compose科学计算器中处理嵌套根号与复杂表达式
问题:处理Jetpack Compose科学计算器中的复杂平方根表达式
我正在用Jetpack Compose开发一款名为"Scientific Calculator"的Android应用,已经实现了√4、√4*2这类简单平方根运算,但处理√(1+2)这类带括号的复杂表达式时遇到困难。需要优化handleSqrtInput函数和evaluate函数,支持嵌套根号和括号的表达式处理与求值。
当前实现
1. ViewModel:handleSqrtInput函数
功能:处理平方根输入,更新显示文本
private fun handleSqrtInput() { if (isResultDisplayed) { displayText = "√" } else { if (displayText == "0") { displayText = "√" } else if (displayText.isNotEmpty()) { val lastChar = displayText.last() when { lastChar.isDigit() -> { try { val res = Math.sqrt(displayText.toDouble()) displayText = res.toString() } catch (e: NumberFormatException) { displayText = "Error" } } lastChar == ')' -> { try { val res = Math.sqrt(displayText.toDouble()) displayText = res.toString() } catch (e: NumberFormatException) { displayText = "Error" } } lastChar.toString().isOperator() -> { displayText += "√" } lastChar == '(' -> { displayText += "√" } lastChar == '√' -> { displayText += "√" } else -> { displayText = displayText.dropLast(1) + "√(" } } } else { displayText = "√(" } } isResultDisplayed = false }
2. Model:evaluate函数
功能:通过栈管理运算符和操作数,求值含平方根的表达式
fun evaluate(expression: String): Double { val operators = Stack<Char>() val operands = Stack<Double>() var i = 0 while (i < expression.length) { when { expression[i] == '√' -> { if (i + 1 < expression.length && expression[i + 1] == '(') { operators.push(expression[i]) } else { i++ val sb = StringBuilder() while (i < expression.length && (expression[i].isDigit() || expression[i] == '.' || expression[i] == '(' || expression[i] == ')')) { sb.append(expression[i]) i++ } val subExpr = sb.toString() operands.push(sqrt(evaluate(subExpr))) i-- } } } i++ } // Add additional logic for handling other operators and completing the expression evaluation }
优化方案
一、ViewModel:优化handleSqrtInput函数
核心改进:智能判断平方根的输入形式,自动补全括号并支持嵌套,保留表达式结构而非直接计算,交给后续求值逻辑处理。
修改后的代码:
private fun handleSqrtInput() { if (isResultDisplayed) { // 结果显示状态下,直接启动新的平方根表达式 displayText = "√(" isResultDisplayed = false return } val currentText = displayText when { currentText == "0" || currentText.isEmpty() -> { displayText = "√(" } else -> { val lastChar = currentText.last() when { // 最后是数字或右括号:自动包裹当前完整表达式 lastChar.isDigit() || lastChar == ')' -> { // 定位需要包裹的表达式起始位置 val startIndex = currentText.findLast { it.isOperator() || it == '(' }?.plus(1) ?: 0 val prefix = currentText.substring(0, startIndex) val exprToWrap = currentText.substring(startIndex) displayText = "$prefix√($exprToWrap)" } // 最后是运算符、左括号、根号:追加带左括号的根号 lastChar.toString().isOperator() || lastChar == '(' || lastChar == '√' -> { displayText += "√(" } else -> { displayText += "√(" } } } } } // 辅助扩展函数:判断是否为运算符 private fun Char.isOperator(): Boolean = this in setOf('+', '-', '*', '/')
关键改动:
- 移除直接计算当前文本的逻辑,保留表达式结构(如
√(1+2)) - 针对不同上下文自动补全括号:数字/右括号后点击√,自动将目标表达式包裹进
√();运算符/左括号/根号后点击√,直接追加√( - 天然支持嵌套根号输入(如连续点击√会生成
√(√(,方便输入多层嵌套表达式)
二、Model:优化evaluate函数
核心改进:完善双栈求值逻辑,明确运算符优先级,正确解析嵌套括号与根号,兼容加减乘除等基础运算。
修改后的代码:
import kotlin.math.sqrt fun evaluate(expression: String): Double { val operators = Stack<Char>() val operands = Stack<Double>() val trimmedExpr = expression.replace("\\s+".toRegex(), "") // 去除表达式中的空格 var i = 0 while (i < trimmedExpr.length) { val c = trimmedExpr[i] when { c.isDigit() || c == '.' -> { // 解析完整数字(含小数) val sb = StringBuilder() while (i < trimmedExpr.length && (trimmedExpr[i].isDigit() || trimmedExpr[i] == '.')) { sb.append(trimmedExpr[i]) i++ } operands.push(sb.toString().toDouble()) continue } c == '(' -> { operators.push(c) } c == ')' -> { // 计算括号内所有运算,直到遇到左括号 while (operators.isNotEmpty() && operators.peek() != '(') { applyOperator(operators, operands) } operators.pop() // 弹出左括号 // 若左括号前是根号,计算根号值 if (operators.isNotEmpty() && operators.peek() == '√') { val value = operands.pop() operands.push(sqrt(value)) operators.pop() } } c == '√' -> { operators.push(c) } c.isOperator() -> { // 按优先级处理栈内运算符:当前运算符优先级更低时,先计算栈顶运算 while (operators.isNotEmpty() && getPrecedence(operators.peek()) >= getPrecedence(c)) { applyOperator(operators, operands) } operators.push(c) } } i++ } // 处理剩余的运算符 while (operators.isNotEmpty()) { applyOperator(operators, operands) } return operands.pop() } private fun Char.isOperator(): Boolean = this in setOf('+', '-', '*', '/') private fun getPrecedence(op: Char): Int { return when (op) { '√' -> 4 // 根号优先级最高 '*', '/' -> 3 '+', '-' -> 2 '(' -> 1 else -> 0 } } private fun applyOperator(operators: Stack<Char>, operands: Stack<Double>) { val op = operators.pop() when (op) { '√' -> { val num = operands.pop() operands.push(sqrt(num)) } '+' -> { val b = operands.pop() val a = operands.pop() operands.push(a + b) } '-' -> { val b = operands.pop() val a = operands.pop() operands.push(a - b) } '*' -> { val b = operands.pop() val a = operands.pop() operands.push(a * b) } '/' -> { val b = operands.pop() if (b == 0.0) throw ArithmeticException("Division by zero") val a = operands.pop() operands.push(a / b) } } }
关键改动:
- 完善双栈求值逻辑,支持根号与加减乘除的混合运算
- 定义明确的运算符优先级,确保根号运算优先执行
- 处理括号时,先完成括号内所有运算,再将结果应用到前置根号
- 原生支持嵌套根号(如
√(√(12+4))会按12+4=16→√16=4→√4=2的顺序计算) - 增加完整的数字解析逻辑,支持小数运算
内容的提问来源于stack exchange,提问作者Sundaram Pandey
相关产品推荐
相关产品推荐

