Reputation: 43
I have the following string, from which I want to remove the currency formatting and extract the numeric value for manipulation:
"Product Price":"\u00a3314.95",
I've tried using the following code:
let productvalue = model[indexPath.row].productPrice ?? ""
let prodval = productvalue.replacingOccurrences(of: "\u00a3", with: "")
let proqty = model[indexPath.row].quantity ?? ""
let totalprice = (Int(prodval)) * (Int(proqty))
However, when I run this code, I am getting the following response from an API:
Binary operator '*' cannot be applied to two 'Int?' operands
Upvotes: 0
Views: 1328
Reputation: 16774
If you look closely the constructors of integers from string return optional values. So what you have is:
let totalprice = {
let a: Int? = Int(prodval)
let b: Int? = Int(proqty)
return a*b // Error
}()
a quick fix is to force-unwrap it using !
resulting in let totalprice = (Int(prodval))! * (Int(proqty))!
but I would not suggest it because it may crash your app.
A but more elegant solution is to use defaults:
let totalprice = {
let a: Int = Int(prodval) ?? 0
let b: Int = Int(proqty) ?? 0
return a*b
}()
But on the other hand why are you even using integers here? What if the price is not a whole number? I suggest you rather use decimal numbers to handle these cases:
let a = NSDecimalNumber(string: prodval)
let b = NSDecimalNumber(string: proqty)
let totalprice = a.multiplying(by: b)
This is now working with decimal numbers directly. To get a double value or integer value you would simply need to use it's properties totalprice.doubleValue
or totalprice.intValue
. But there is no need for that either. If you need to convert it back to string simply use formatters:
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencySymbol = "$"
let finalOutput: String = formatter.string(from: totalprice)
There are many possible solutions to this and if possible I would try to do it all with formatters and decimal numbers. For instance in your case something like the following might do the trick:
private func generateFormatter(currencySymbol: String = "$", decimalSeparator: String = ".") -> NumberFormatter {
let formatter = NumberFormatter()
formatter.currencySymbol = currencySymbol
formatter.decimalSeparator = decimalSeparator
formatter.numberStyle = .currency
return formatter
}
private func parseValue(_ input: String?, formatterInfo: (currencySymbol: String, decimalSeparator: String)) -> NSNumber? {
guard let input = input else { return nil }
let formatter = generateFormatter(currencySymbol: formatterInfo.currencySymbol, decimalSeparator: formatterInfo.decimalSeparator)
return formatter.number(from: input)
}
private func multiplyValues(_ values: [String?], formatterInfo: (currencySymbol: String, decimalSeparator: String)) throws -> NSNumber {
return try values.reduce(NSDecimalNumber(value: 1.0)) { result, value in
guard let parsedValue = parseValue(value, formatterInfo: formatterInfo) else {
throw NSError(domain: "Parsing values", code: 400, userInfo: ["dev_message": "Could not parse a value \(value ?? "[Null value]")"])
}
return NSDecimalNumber(decimal: result.decimalValue).multiplying(by: NSDecimalNumber(decimal: parsedValue.decimalValue))
}
}
let values = ["$1.2", "$1.6", "$2"]
let result = try? multiplyValues(values, formatterInfo: ("$", "."))
let parsedResult: String = {
guard let result = try? multiplyValues(values, formatterInfo: ("$", ".")) else { return "Could not produce result" }
return generateFormatter(currencySymbol: "$", decimalSeparator: ".").string(from: result) ?? "Could not format result"
}()
print(result ?? "No result")
print(parsedResult)
I hope the code speaks for itself and you can see it is easy to change/inject different formats/symbols.
Upvotes: 0
Reputation: 907
You can convert currency string to decimal
let str = "£300"
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencyCode = "GBP"
if let number = formatter.number(from: str) {
let amount = number.decimalValue
print(amount)
}
Upvotes: 0
Reputation: 52013
The problem is that the init methods you use returns an optional value so you need to include a value in case the conversion from String to Int returns nil like
let value = Int(someString) ?? 0
but in your case you are dealing with decimal values so you need to convert to Double
let totalprice = (Double(prodval) ?? 0.0) * (Double(proqty) ?? 0.0)
Upvotes: 1
Reputation: 8680
You can use this extension that will help you remove currency symbols from the amount.
Replace your desired currency with $ for example use € instead of unicode.
extension String {
func removeFormatAmount() -> Double {
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "en_US")
formatter.numberStyle = .currency
formatter.currencySymbol = "$"
formatter.decimalSeparator = ","
return formatter.number(from: self) as Double? ?? 0
}
}
How to use this extension.
let currencyString = "$1,000.00"
let amount = currencyString.removeFormatAmount() // 1000.0
Upvotes: 1