Converting Infix Expressions to Postfix and Evaluating Them in Swift
This article explains how to transform a typical infix arithmetic expression such as "8 - (6 + 4 / 2 - 1) * 2" into a postfix (Reverse Polish) form using Swift, then evaluates the postfix expression step by step with custom Swift functions and also shows a shortcut using NSExpression.
Background : While developing a "24‑point challenge" app the author needed to compute the result of arbitrary arithmetic strings like 8 - (6 + 4 / 2 - 1) * 2 and show the whole calculation process.
Infix vs. Postfix : An infix expression places operators between operands, which is natural for humans but difficult for computers. Converting it to postfix (Reverse Polish) puts the operator after its operands, making evaluation straightforward.
Conversion algorithm : The algorithm uses two arrays to simulate a stack (one for numbers, one for operators). It scans the expression from left to right, handling parentheses, operator precedence, and finally outputs the postfix array.
Swift implementation – conversion :
func converExpressionToSuffixExpression(_ expressionStr: String) -> [String] {
var suffixExpressionList: [String] = []
var operatorExpressionList: [String] = []
for item in expressionStr {
let itemStr = String(item)
if itemStr == " " { continue }
if item.isNumber {
suffixExpressionList.append(itemStr)
} else {
if operatorExpressionList.isEmpty {
operatorExpressionList.append(itemStr)
} else {
if itemStr == ")" {
let temp = handleAppendExpressionList(operatorExpressionList, suffixList: suffixExpressionList, isRightBracket: true)
operatorExpressionList = temp.l1
suffixExpressionList = temp.l2
} else {
let lastStr = operatorExpressionList.last!
let isItemPriorityHigh = isFirstOperatorPriorityHigh(first: itemStr, second: lastStr)
if isItemPriorityHigh || itemStr == "(" || lastStr == "(" {
operatorExpressionList.append(itemStr)
} else {
let temp = handleAppendExpressionList(operatorExpressionList, suffixList: suffixExpressionList, isRightBracket: false)
operatorExpressionList = temp.l1
suffixExpressionList = temp.l2
operatorExpressionList.append(itemStr)
}
}
}
}
}
while !operatorExpressionList.isEmpty {
if let last = operatorExpressionList.popLast() {
suffixExpressionList.append(last)
}
}
return suffixExpressionList
}
func handleAppendExpressionList(_ operatorList: [String], suffixList: [String], isRightBracket: Bool) -> ([String], [String]) {
var operatorExpressionList = operatorList
var suffixExpressionList = suffixList
var lastStr = operatorExpressionList.last
repeat {
guard let tempLastStr = operatorExpressionList.popLast() else { break }
lastStr = tempLastStr
if tempLastStr != "(" {
suffixExpressionList.append(tempLastStr)
} else if isRightBracket {
operatorExpressionList.append("(")
}
} while lastStr != "(" && lastStr != ""
return (operatorExpressionList, suffixExpressionList)
}
func isFirstOperatorPriorityHigh(first: String, second: String) -> Bool {
let isFirst = isMultiplyOrDivideOperator(itemStr: first)
let isSecond = isMultiplyOrDivideOperator(itemStr: second)
return isFirst && !isSecond
}
func isMultiplyOrDivideOperator(itemStr: String) -> Bool {
return ["*", "x", "×", "X", "/", "÷"].contains(itemStr)
}Postfix evaluation principle : Scan the postfix array from left to right; when an operator is encountered, take the two preceding numbers, compute a op b, replace the three elements with the result, and continue until a single element remains.
Swift implementation – evaluation :
func calculatorExpressionList(_ expressionList: [String]) -> Double {
if expressionList.count == 1 {
return (expressionList.first as NSString?)?.doubleValue ?? 0.0
}
var targetList = expressionList
for (index, item) in expressionList.enumerated() {
if isOperator(item) {
let a = expressionList[index - 2]
let b = expressionList[index - 1]
let r = calculator(a, item, b)
targetList[index - 2] = r
targetList.removeSubrange(Range(NSRange(location: index - 1, length: 2))!)
break
}
}
return calculatorExpressionList(targetList)
}
func calculator(_ a: String, _ op: String, _ b: String) -> String {
let aValue = (a as NSString).doubleValue
let bValue = (b as NSString).doubleValue
var result: Double = 0.0
switch op {
case "+": result = aValue + bValue
case "-": result = aValue - bValue
case "*", "×", "x", "X": result = aValue * bValue
case "/", "÷": if bValue != 0 { result = aValue / bValue }
default: break
}
return String(format: "%f", result)
}
func isOperator(_ str: String) -> Bool {
if isMultiplyOrDivideOperator(itemStr: str) { return true }
return str == "+" || str == "-"
}Shortcut with NSExpression : For simple calculations the built‑in NSExpression class can evaluate a formatted string directly.
let expressionStr = "2 + 3 * (5 - 1)"
let formatted = expressionStr.replacingOccurrences(of: " ", with: "")
let expression = NSExpression(format: formatted)
if let result = expression.expressionValue(with: nil, context: nil) as? NSNumber {
print(result)
}Summary : The article provides a complete Swift solution for converting infix arithmetic strings to postfix notation, evaluating the postfix expression, and an alternative using NSExpression. The full source code is available at GitHub .
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
