7

I am trying to duplicate Need to write calculator in Objective-C in Swift but my code is not working.

import Foundation

var equation:NSString = "5*(2.56-1.79)-4.1"

var result = NSExpression(format: equation, argumentArray: nil)

println(result)
Community
  • 1
  • 1
Chéyo
  • 9,107
  • 9
  • 27
  • 44
  • `result` is `NSExpression`, not the result. You need to call `result.expressionValue(object:nil context:nil)`, and call `floatValue` (unless `NSNumber` is acceptable). – Sergey Kalinichenko Jul 11 '14 at 18:23

2 Answers2

13

As already said in a comment, you have to call expressionValueWithObject() on the expression:

let expr = NSExpression(format: equation)
if let result = expr.expressionValueWithObject(nil, context: nil) as? NSNumber {
    let x = result.doubleValue
    println(x)
} else {
    println("failed")
}

Update for Swift 3:

let expr = NSExpression(format: equation)
if let result = expr.expressionValue(with: nil, context: nil) as? Double {
    print(result) // -0.25
} else {
    print("failed")
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • 1
    good stuff! i was a bit puzzled why my expression `var equation = "11 / 2"` would evaluate to `5.0` though. i figured it needed values to be specified as doubles in the string itself -- `var equation = "11.0 / 2.0" // 5.5`. – joe Jan 14 '15 at 23:27
4

Details

  • Xcode 9.4.1, Swift 4.1
  • Xcode 10.2.1 (10E1001), Swift 5

Solution

import Foundation

extension String {

    private func allNumsToDouble() -> String {

        let symbolsCharSet = ".,"
        let fullCharSet = "0123456789" + symbolsCharSet
        var i = 0
        var result = ""
        var chars = Array(self)
        while i < chars.count {
            if fullCharSet.contains(chars[i]) {
                var numString = String(chars[i])
                i += 1
                loop: while i < chars.count {
                    if fullCharSet.contains(chars[i]) {
                        numString += String(chars[i])
                        i += 1
                    } else {
                        break loop
                    }
                }
                if let num = Double(numString) {
                    result += "\(num)"
                } else {
                    result += numString
                }
            } else {
                result += String(chars[i])
                i += 1
            }
        }
        return result
    }

    func calculate() -> Double? {
        let transformedString = allNumsToDouble()
        let expr = NSExpression(format: transformedString)
        return expr.expressionValue(with: nil, context: nil) as? Double
    }
}

Usage

"3*(3-1)-5".calculate()

Full sample

    func test(_ expressrion: String) {
    if let num = expressrion.calculate() {
        print("\(expressrion) = \(num)")
    } else {
        print("\(expressrion) = nil")
    }
}

test("3*(3-1)-5")
test("5.2*(2-1.79)-5.1")
test("11/5")

Results

enter image description here

Vasily Bodnarchuk
  • 24,482
  • 9
  • 132
  • 127