Created
May 27, 2022 01:44
-
-
Save reisdev/6482f868ff876934c94896e94a6cb314 to your computer and use it in GitHub Desktop.
Handmade function to evaluate math expressions within strings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func calc(_ expression: String) -> Double { | |
var elements: [String] = [] | |
let operators = ["*","/","+","-"] | |
var current = "" | |
for item in expression { | |
let char = String(item) | |
let last = elements.last ?? "" | |
if char == " " { | |
continue | |
} else if Double(char) != nil || char == "." || | |
(char == "-" && current.count == 0 && (last == "" || operators.contains(last))) { | |
current += char | |
} else { | |
if(current.count > 0) { | |
elements.append(current) | |
current = "" | |
} | |
elements.append(char) | |
} | |
} | |
if current.count > 0 { | |
elements.append(current) | |
} | |
var element = "" | |
var i = 0, result = 0.0 | |
if elements.contains("(") { | |
i = elements.lastIndex { $0 == "(" } ?? 0 | |
} else if elements.contains("*") || elements.contains("/") { | |
i = (elements.firstIndex { $0 == "*" || $0 == "/" } ?? 0) | |
} | |
while i < elements.count { | |
element = elements[i] | |
if operators.contains(element) { | |
var left: Double? = nil, right: Double? = nil | |
if i > 0 { | |
left = Double(elements[i-1]) | |
} | |
if i < elements.count - 1 { | |
right = Double(elements[i+1]) | |
} | |
if let leftNumber = left,let rightNumber = right { | |
switch element { | |
case "+": | |
result = leftNumber + rightNumber | |
case "-": | |
result = leftNumber - rightNumber | |
case "*": | |
result = leftNumber * rightNumber | |
case "/": | |
result = leftNumber / rightNumber | |
default: break | |
} | |
elements.removeSubrange(i-1...i+1) | |
elements.insert(String(result),at: i-1) | |
i = 0 | |
continue | |
} else if let rightNumber = right { | |
if element == "-" { | |
result = -rightNumber | |
} else { | |
result = rightNumber | |
} | |
elements.removeSubrange(i...i+1) | |
elements.insert(String(result),at: i) | |
i = 0 | |
continue | |
} else { | |
i += 1 | |
continue | |
} | |
} else if element == "(" { | |
let closingIndex = elements[i..<elements.count].firstIndex { $0 == ")" } ?? (elements.count-1) | |
let subExpression = elements[i+1..<closingIndex] | |
let result = calc(subExpression.joined(separator: "")) | |
elements.removeSubrange(i...closingIndex) | |
elements.insert(String(result),at: i) | |
i = 0 | |
} | |
if elements.contains("(") { | |
i = elements.lastIndex { $0 == "(" } ?? 0 | |
} else if elements.contains("*") || elements.contains("/") { | |
i = (elements.firstIndex { $0 == "*" || $0 == "/" } ?? 0) | |
} else { | |
i+=1 | |
} | |
} | |
result = Double(elements.first ?? "") ?? 0.0 | |
if elements.count > 1 { | |
result = elements.reduce(0) { (partial: Double, next: String) in | |
return partial + (Double(next) ?? 0.0) | |
} | |
} | |
return result | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment