Using Swift how to convert a string to a number - ios

I am getting values back from a web service that gives me back prices in a string format, this is put into a Dictionary, so I get prices back as "1.5000" for example, which is obviously 1.50 in currency. However for the life of me I cannot get anything to work in Swift to format this correctly. In most other languages you can do this in a couple of seconds, so I'm getting a bit frustrated with something that is so simple.
Here's my test code:
var testnumber = "1.5000"
let n = NSNumberFormatter()
n.numberStyle = NSNumberFormatterStyle.DecimalStyle
n.maximumFractionDigits = 2
n.minimumFractionDigits = 2
let returnNumber = n.numberFromString(testnumber)
println("Returned number is \(returnNumber)")
This prints out in debug "number is Optional(1.5)" not 1.50!
I have changed NSNumberFormatterStyle.DecimalStyle to NSNumberFormatterStyle.CurrencyStyle as I thought that may do it for me as the returned number is a currency anyway, but that gives me back in debug "Returned number is nil" - which is even more confusing to me!
I have tried using maximumIntegerDigits and minimumIntegerDigits, setting locales using n.locale = NSLocale.currentLocale(), setting formatWidth, setting paddingPosition and paddingCharacter but nothing helps, I either get nil back to 1.5.
All I ultimately need to do is convert a string to a float or a currency value, and ensure there are 2 decimal places, and I can't believe it's this hard to accomplish!
Any help would be very gratefully received.

You are printing a number not a string
Xcode 11.4 • Swift 5.2 or later
extension Formatter {
static let usCurrency: NumberFormatter = {
let formatter = NumberFormatter()
formatter.locale = .init(identifier: "en_US")
formatter.numberStyle = .currency
return formatter
}()
}
extension String {
var double: Double? { Double(self) }
var usCurrencyFormatted: String {
Formatter.usCurrency.string(for: double) ?? Formatter.usCurrency.string(for: 0) ?? ""
}
}
"1.1222".usCurrencyFormatted // "$1.12"
"2".usCurrencyFormatted // "$2.00"

The problem is about numberFromString returning an optional - so you have to unwrap before printing. Just to be safe, you can use optional binding:
if let returnNumber = n.numberFromString(testnumber) {
println("Returned number is \(returnNumber)")
}
otherwise if it's ok for the app to crash if the optional is nil (in some cases this is a wanted behavior if the optional is expected to always contain a non nil value) just use forced unwrapping:
let returnNumber = n.numberFromString(testnumber)!
println("Returned number is \(returnNumber)")
That fixes the unwanted "Optional(xx)" text. As for formatting a float/double number, there are probably several ways of doing it - the one I would use is c-like string formatting, available via NSString:
let formattedNumber = NSString(format: "%.2f", returnNumber)
println("Returned number is \(formattedNumber)")
Use String Format Specifiers as reference if you want to know more about format specifiers.

You could probably just use the NSNumberFormatter that you just created.
let returnNumber = n.stringFromNumber(n.numberFromString(testnumber))
returnNumber will now be of type String.

The following returns to 2 decimal places for me in playgrounds. May be of some help to you. Uses NSNumberFormatter and then unwraps the optional
let testnumber: String = "1.50000"
let numberFormatter = NSNumberFormatter()
let number = numberFormatter.numberFromString(testnumber)
if let final = number?.floatValue {
println("Returned number is " + String(format: "%.2f", final))
}

Related

Converting a value to double always returns sceintific format in Swift

I am getting some coordinates from server in string array. And I am trying to save those coordinates in SQLite Database by splitting and converting them to double value. But some coordinates are getting saved in scientific notations. For example I am getting the following coordinate from server:
"-0.0000558,51.3368066"
I am splitting the string and converting it to double resulting in the following values:
[-5.58e-05,51.3368066]
I have tried following solutions but still returning same result:
1.
Double(latLongArr[0])
extension String{
var doubleValue: Double? {
return NumberFormatter().number(from: self)?.doubleValue
}
}
extension String{
var doubleValue: Double? {
let numberFormatter = NumberFormatter()
numberFormatter.allowsFloats = true
numberFormatter.maximumFractionDigits = 10
numberFormatter.numberStyle = .decimal
return numberFormatter.number(from: "\(self)")!.doubleValue
}
}
I have used the above code but it still returns in scientific format but I need it in normal decimal format. So what is the issue?
The last option is the option I would go for and I believe it works right.
I believe your issue is only when you print to console:
As you can see, the double variable is actually converted properly but just when it is formatted to print to the console it shows it as a scientific notation string.
Your other option besides using doubleValue is to use decimalValue
I suggest putting a breakpoint and checking the actual value of your double than reviewing it from the console output which is a formatted string.
Just for reference, code used in the image above:
let number = "-0.0000558"
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.maximumFractionDigits = 10
let finalNumber = numberFormatter.number(from: number)
let decimalNumber = finalNumber!.decimalValue
let doubleNumber = finalNumber!.doubleValue
print(decimalNumber)
print(doubleNumber)
If you want to print your Doubles without scientific notation use
String(format: "%.7f", value).
Example:
let value = Double(3.141592)
print(String(format: "%.7", value)
will print 3.1415920.
I have used the below extension to represent scientific values in the decimal format.
extension String {
func getDecimalValue() -> Decimal{
return NSNumber(value: Double(self)!).decimalValue
}
}
Usage:
let numberString = "+5.58e-05"
print(numberString.getDecimalValue()) //0.0000558

Can't get correct number formatting as a string [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 2 years ago.
I've developed a custom control for money input, which contains UITextField and UILabel. When the user taps on it, it becomes active and switches to the UITextField for data input and accepts only numbers and dot symbol, when the user finishes editing it becomes passive and switches to UILabel just to show formatted money value. But there is one little issue which I'm unable to fix a lot of days already.
Let's say the user writes down 88.99 and presses done, this becomes "$ 88.99" in a UILabel, next when the user again taps on it to edit the initial value I get the following value "88.98999999999999". To not present the entire code I selected the core part in a playground format which gives the same result as in my complete project:
extension NumberFormatter {
static public func defaultCurrencyFormatter() -> NumberFormatter {
let formatter = NumberFormatter()
formatter.usesGroupingSeparator = true
formatter.numberStyle = .currency
formatter.currencySymbol = ""
formatter.minimumFractionDigits = 1
formatter.maximumFractionDigits = 2
formatter.currencyGroupingSeparator = ","
formatter.currencyDecimalSeparator = "."
return formatter
}
}
let stringValue = NumberFormatter.defaultCurrencyFormatter().number(from: "88.99")?.stringValue
print(stringValue) // result is Optional("88.98999999999999")
I have no idea why using this NumberFormatter I get such a result. I was thinking that explicitly setting minimumFractionDigits and maximumFractionDigits will solve my issue but it does not affect my result
NumberFormatter is legacy from objc and it operates with NSNumber/CGFloat etc. and usually it is helpful for localized text formatting. Much powerful and convenient parser for numbers is Scanner but if you don't have complex data structure to parse and don't want to deal with Floating-point error mitigation just use swift's Float:
// Float from string
if let float = Float("88.99") {
print(float)
// String from float
let text = String(float)
print(text)
}
Prints:
88.99
88.99
Try this:
extension String {
var currencyStyle: String? {
let formatter = NumberFormatter()
formatter.minimumFractionDigits = 1
formatter.maximumFractionDigits = 2
formatter.usesGroupingSeparator = true
formatter.groupingSize = 3
formatter.currencyGroupingSeparator = ","
formatter.currencyDecimalSeparator = "."
if let double = Double(self) {
let number = NSNumber(value: double)
return formatter.string(from: number)
}
return nil
}
}
to use it:
let str = "12388.98999999999999".currencyStyle
print(str) // Optional("12,388.99")

Is it me or is NSNumberFormatter broken? [duplicate]

I'm seeing some strange bugs in my iPhone app that I have narrowed down to my use of NSNumberFormatter.
A stripped down example...
In Xcode playground I have:
let numberFormatter = NSNumberFormatter()
//numberFormatter.numberStyle = .DecimalStyle - does not change behavior
let numberString = "546000.06"
let number: NSNumber = numberFormatter.numberFromString(numberString)!
print("number: \(number)")
let number1: NSNumber = NSDecimalNumber(string: numberString)
print("number1: \(number1)")
This is the output:
number: 546000.0600000001
number1: 546000.06
Note that setting the numberStyle to .DecimalStyle doesn't change anything.
This issue only happens for certain numeric values (for example, 8.03 is another one). I thought NSNumberFormatter was safe for this type of conversion and I haven't seen much noise about this issue on the internet so I want to assume it is something I am doing wrong.
Can anyone explain what I am seeing? Any help is very much appreciated!
It looks like there is an issue with NSNumberFormatter. There are certain values where this rounding error creeps up. In the XCode 7.2.1 playground, it shows up around 8.03.
One way that I've solved this is to round the decimal number. Since the difference is +/- a tiny amount, rounding to 4 fraction places should work. You can use various rounding modes. In this example I used RoundPlain.
var initialValue = NSDecimalNumber(string: "7")
let handler = NSDecimalNumberHandler(roundingMode: NSRoundingMode.RoundPlain, scale: 4, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false)
let numberFormatter = NSNumberFormatter()
for index in 1...300 {
initialValue = initialValue.decimalNumberByAdding(0.01)
let stringValue = "\(initialValue)"
var number = numberFormatter.numberFromString(stringValue)
var decimalNumber: NSDecimalNumber = NSDecimalNumber(decimal: number!.decimalValue)
decimalNumber = decimalNumber.decimalNumberByRoundingAccordingToBehavior(handler)
print("stringValue = \(stringValue), decimalNumber = \(decimalNumber), number = \(number!)")
}
You are seeing a rounding error.
If you would like to display a number to the user with two fraction digits, set maximumFractionDigits:
let numberFormatter = NSNumberFormatter()
numberFormatter.maximumFractionDigits = 2
let firstNumber = NSNumber(float:546000.06)
let firstNumberString = numberFormatter.stringFromNumber(firstNumber)!
let secondNumber = NSNumber(float:5.1337)
let secondNumberString = numberFormatter.stringFromNumber(secondNumber)!
print("firstNumber: \(firstNumberString)")
print("secondNumber: \(secondNumberString)")
The output will be:
"firstNumber: 546000.06\n"
"secondNumber: 5.13\n"
If you try to parse a number from a string, then you are all set.
let thirdNumber = numberFormatter.numberFromString("546000.06")!
print("thirdNumber \(thirdNumber.className): \(thirdNumber)")
The last line prints the description of the object itself (w/ rounding error):
"thirdNumber __NSCFNumber: 546000.0600000001\n"
Update (2016-03-18)
You want to parse the following string:
let currencyString = "$546,000.06"
First, we create a formatter with a locale and .CurrencyStyle. Be aware that the locale depends on the string you try to parse and not on the system you are running on.
let currencyFormatter = NSNumberFormatter.init()
currencyFormatter.locale = NSLocale.init(localeIdentifier: "en_US")
currencyFormatter.numberStyle = .CurrencyStyle
We can now use the formatter to prase the string.
let currencyNumber = currencyFormatter.numberFromString(currencyString)!
You are now free to store this object, for example in CoreData. However, if you wan't to present the value to the user (or print it on the console), you have to use a NSNumberFormatter. If you print the object directly, the description (or debugDescription) of the object is used.
So, let's create another formatter to print the value of your NSNumber object:
let outputFormatter = NSNumberFormatter.init()
outputFormatter.maximumFractionDigits = 10
Using many fraction digits should print any possible rounding errors. But
print("Number: \(outputFormatter.stringFromNumber(currencyNumber)!)")
outputs the desired result:
"Number: 546000.06\n"
What you have seen is the result of the internal representation of an NSNumber object (with description/debugDescription).

NSNumberFormatter numberFromString is adding a small fraction when converting certain numbers

I'm seeing some strange bugs in my iPhone app that I have narrowed down to my use of NSNumberFormatter.
A stripped down example...
In Xcode playground I have:
let numberFormatter = NSNumberFormatter()
//numberFormatter.numberStyle = .DecimalStyle - does not change behavior
let numberString = "546000.06"
let number: NSNumber = numberFormatter.numberFromString(numberString)!
print("number: \(number)")
let number1: NSNumber = NSDecimalNumber(string: numberString)
print("number1: \(number1)")
This is the output:
number: 546000.0600000001
number1: 546000.06
Note that setting the numberStyle to .DecimalStyle doesn't change anything.
This issue only happens for certain numeric values (for example, 8.03 is another one). I thought NSNumberFormatter was safe for this type of conversion and I haven't seen much noise about this issue on the internet so I want to assume it is something I am doing wrong.
Can anyone explain what I am seeing? Any help is very much appreciated!
It looks like there is an issue with NSNumberFormatter. There are certain values where this rounding error creeps up. In the XCode 7.2.1 playground, it shows up around 8.03.
One way that I've solved this is to round the decimal number. Since the difference is +/- a tiny amount, rounding to 4 fraction places should work. You can use various rounding modes. In this example I used RoundPlain.
var initialValue = NSDecimalNumber(string: "7")
let handler = NSDecimalNumberHandler(roundingMode: NSRoundingMode.RoundPlain, scale: 4, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false)
let numberFormatter = NSNumberFormatter()
for index in 1...300 {
initialValue = initialValue.decimalNumberByAdding(0.01)
let stringValue = "\(initialValue)"
var number = numberFormatter.numberFromString(stringValue)
var decimalNumber: NSDecimalNumber = NSDecimalNumber(decimal: number!.decimalValue)
decimalNumber = decimalNumber.decimalNumberByRoundingAccordingToBehavior(handler)
print("stringValue = \(stringValue), decimalNumber = \(decimalNumber), number = \(number!)")
}
You are seeing a rounding error.
If you would like to display a number to the user with two fraction digits, set maximumFractionDigits:
let numberFormatter = NSNumberFormatter()
numberFormatter.maximumFractionDigits = 2
let firstNumber = NSNumber(float:546000.06)
let firstNumberString = numberFormatter.stringFromNumber(firstNumber)!
let secondNumber = NSNumber(float:5.1337)
let secondNumberString = numberFormatter.stringFromNumber(secondNumber)!
print("firstNumber: \(firstNumberString)")
print("secondNumber: \(secondNumberString)")
The output will be:
"firstNumber: 546000.06\n"
"secondNumber: 5.13\n"
If you try to parse a number from a string, then you are all set.
let thirdNumber = numberFormatter.numberFromString("546000.06")!
print("thirdNumber \(thirdNumber.className): \(thirdNumber)")
The last line prints the description of the object itself (w/ rounding error):
"thirdNumber __NSCFNumber: 546000.0600000001\n"
Update (2016-03-18)
You want to parse the following string:
let currencyString = "$546,000.06"
First, we create a formatter with a locale and .CurrencyStyle. Be aware that the locale depends on the string you try to parse and not on the system you are running on.
let currencyFormatter = NSNumberFormatter.init()
currencyFormatter.locale = NSLocale.init(localeIdentifier: "en_US")
currencyFormatter.numberStyle = .CurrencyStyle
We can now use the formatter to prase the string.
let currencyNumber = currencyFormatter.numberFromString(currencyString)!
You are now free to store this object, for example in CoreData. However, if you wan't to present the value to the user (or print it on the console), you have to use a NSNumberFormatter. If you print the object directly, the description (or debugDescription) of the object is used.
So, let's create another formatter to print the value of your NSNumber object:
let outputFormatter = NSNumberFormatter.init()
outputFormatter.maximumFractionDigits = 10
Using many fraction digits should print any possible rounding errors. But
print("Number: \(outputFormatter.stringFromNumber(currencyNumber)!)")
outputs the desired result:
"Number: 546000.06\n"
What you have seen is the result of the internal representation of an NSNumber object (with description/debugDescription).

String to Double in XCode 6's Swift [duplicate]

This question already has answers here:
Swift - How to convert String to Double
(30 answers)
Closed 7 years ago.
How do I convert a string to double in Swift? I've tried string.doubleValue or string.bridgeToObjectiveC().doubleValue and none of it works. Any ideas?
You can create a read-only computed property string extension to help you convert your strings to double:
You can use NSNumberFormatter
extension String {
struct Number {
static let formatter = NSNumberFormatter()
}
var doubleValue: Double {
return Number.formatter.numberFromString(self)?.doubleValue ?? 0
}
}
or you can cast it to NSString and extract its doubleValue property:
extension String {
var ns: NSString {
return self
}
var doubleValue: Double {
return ns.doubleValue
}
}
"2.35".doubleValue + 3.3 // 5.65
According to Stanford CS193p course Winter 2015, the correct way to get a double from a String in Swift is to use NSNumberFormatter instead of NSString:
let decimalAsString = "123.45"
let decimalAsDouble = NSNumberFormatter().numberFromString(decimalAsString)!.doubleValue
If you want to be safe (regarding the optional unwrapping and the decimal separator), you'd use:
let decimalAsString = "123.45"
var formatter = NSNumberFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US")
if let decimalAsDoubleUnwrapped = formatter.numberFromString(decimalAsString) {
decimalAsDouble = decimalAsDoubleUnwrapped.doubleValue
}
Safe unwrapping is particularly useful if you parse a XML or JSON file and you need to make sure you have a String that can be converted into a Double (the program will crash if you force-unwrap an optional that is actually nil).
/!\
EDIT: be careful, NSNumberFormatter works differently than NSString.
NSString allowed you to do things like : (dictionary[key] as NSString).doubleValue, provided that dictionary[key] used the '.' as decimal separator (like in "123.45").
But NSNumberFormatter(), by default, initializes an instance of NSNumberFormatter with your current system Locale!
Therefore, NSNumberFormatter().numberFromString(decimalAsString)!.doubleValue would work with 123.45 on a US device, but not on a French one for example!
If you are parsing a JSON file for example, and you know that values are stored using '.' as the decimal separator, you need to set the locale of your NSNumberFormatter instance accordingly:
var formatter = NSNumberFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US")
then:
let decimalAsString = "123.45"
if let decimalAsDoubleUnwrapped = NSNumberFormatter().numberFromString(decimalAsString) {
decimalAsDouble = decimalAsDoubleUnwrapped.doubleValue
}
In that case, decimalAsDouble will correctly return 123.45 as a doubleValue.
But it would return nil if decimalAsString = "123,45".
Or if the NSLocale was set as "fr_FR".
On the other hand, a NSNumberFormatter using a NSLocale with fr_FR would work perfectly with "123,45", but return nil with "123.45".
I thought that was worth reminding.
I updated my answer accordingly.
EDIT : also, NSNumberFormatter wouldn't know what do with things like "+2.45%" or "0.1146"(you would have to define the properties of your NSNumberFormatter instance very precisely). NSString natively does.
you can always just cast from String to NSString like this
let str = "5"
let dbl = (str as NSString).doubleValue
Try this :
var a:Double=NSString(string: "232.3").doubleValue
Try this:
let str = "5"
let double = Double(str.toInt()!)
another way is:
let mySwiftString = "5"
var string = NSString(string: mySwiftString)
string.doubleValue
this latter one posted here:
Swift - How to convert String to Double

Resources