If I have a string that has an arithmetic expression with paranthesis like:
((4 * 7) / 2) - 7
How do I evaluate it automatically? In particular with Kotlin. I heard that you need to make a parser, so how can I do so in Kotlin and have all the necessary basic operations in the example as such?
CodePudding user response:
fun evaluate(str: String): Double {
data class Data(val rest: List<Char>, val value: Double)
return object : Any() {
fun parse(chars: List<Char>): Double {
return getExpression(chars.filter { it != ' ' })
.also { if (it.rest.isNotEmpty()) throw RuntimeException("Unexpected character: ${it.rest.first()}") }
.value
}
private fun getExpression(chars: List<Char>): Data {
var (rest, carry) = getTerm(chars)
while (true) {
when {
rest.firstOrNull() == ' ' -> rest = getTerm(rest.drop(1)).also { carry = it.value }.rest
rest.firstOrNull() == '-' -> rest = getTerm(rest.drop(1)).also { carry -= it.value }.rest
else -> return Data(rest, carry)
}
}
}
fun getTerm(chars: List<Char>): Data {
var (rest, carry) = getFactor(chars)
while (true) {
when {
rest.firstOrNull() == '*' -> rest = getTerm(rest.drop(1)).also { carry *= it.value }.rest
rest.firstOrNull() == '/' -> rest = getTerm(rest.drop(1)).also { carry /= it.value }.rest
else -> return Data(rest, carry)
}
}
}
fun getFactor(chars: List<Char>): Data {
return when (val char = chars.firstOrNull()) {
' ' -> getFactor(chars.drop(1)).let { Data(it.rest, it.value) }
'-' -> getFactor(chars.drop(1)).let { Data(it.rest, -it.value) }
'(' -> getParenthesizedExpression(chars.drop(1))
in '0'..'9', ',' -> getNumber(chars)
else -> throw RuntimeException("Unexpected character: $char")
}
}
fun getParenthesizedExpression(chars: List<Char>): Data {
return getExpression(chars)
.also { if (it.rest.firstOrNull() != ')') throw RuntimeException("Missing closing parenthesis") }
.let { Data(it.rest.drop(1), it.value) }
}
fun getNumber(chars: List<Char>): Data {
val s = chars.takeWhile { it.isDigit() || it == '.' }.joinToString("")
return Data(chars.drop(s.length), s.toDouble())
}
}.parse(str.toList())
}
val expresssion = "((4 * 7) / 2) - 7"
val result = evaluate(expresssion)
println(result) // Output: 7.0