Swift - How to convert String to Double
I'm trying to write a BMI program in swift language. And I got this problem: how to convert a String to a Double?
In Objective-C, I can do like this:
double myDouble = [myString doubleValue];
But how can I achieve this in Swift language?
Swift 2 Update
There are new failable initializers that allow you to do this in more idiomatic and safe way (as many answers have noted, NSString's double value is not very safe because it returns 0 for non number values. This means that the doubleValue
of "foo"
and "0"
are the same.)
let myDouble = Double(myString)
This returns an optional, so in cases like passing in "foo"
where doubleValue
would have returned 0, the failable intializer will return nil
. You can use a guard
, if-let
, or map
to handle the Optional<Double>
Original Post: You don't need to use the NSString constructor like the accepted answer proposes. You can simply bridge it like this:
(swiftString as NSString).doubleValue
Swift 4.2+ String to Double
You should use the new type initializers to convert between String and numeric types (Double, Float, Int). It'll return an Optional type (Double?) which will have the correct value or nil if the String was not a number.
Note: The NSString doubleValue property is not recommended because it returns 0 if the value cannot be converted (i.e.: bad user input).
let lessPrecisePI = Float("3.14")
let morePrecisePI = Double("3.1415926536")
let invalidNumber = Float("alphabet") // nil, not a valid number
Unwrap the values to use them using if/let
if let cost = Double(textField.text!) {
print("The user entered a value price of \(cost)")
} else {
print("Not a valid number: \(textField.text!)")
}
You can convert formatted numbers and currency using the NumberFormatter
class.
let formatter = NumberFormatter()
formatter.locale = Locale.current // USA: Locale(identifier: "en_US")
formatter.numberStyle = .decimal
let number = formatter.number(from: "9,999.99")
Currency formats
let usLocale = Locale(identifier: "en_US")
let frenchLocale = Locale(identifier: "fr_FR")
let germanLocale = Locale(identifier: "de_DE")
let englishUKLocale = Locale(identifier: "en_GB") // United Kingdom
formatter.numberStyle = .currency
formatter.locale = usLocale
let usCurrency = formatter.number(from: "$9,999.99")
formatter.locale = frenchLocale
let frenchCurrency = formatter.number(from: "9999,99€")
// Note: "9 999,99€" fails with grouping separator
// Note: "9999,99 €" fails with a space before the €
formatter.locale = germanLocale
let germanCurrency = formatter.number(from: "9999,99€")
// Note: "9.999,99€" fails with grouping separator
formatter.locale = englishUKLocale
let englishUKCurrency = formatter.number(from: "£9,999.99")
Read more on my blog post about converting String to Double types (and currency).
For a little more Swift feeling, using NSFormatter()
avoids casting to NSString
, and returns nil
when the string does not contain a Double
value (e.g. "test" will not return 0.0
).
let double = NSNumberFormatter().numberFromString(myString)?.doubleValue
Alternatively, extending Swift's String
type:
extension String {
func toDouble() -> Double? {
return NumberFormatter().number(from: self)?.doubleValue
}
}
and use it like toInt()
:
var myString = "4.2"
var myDouble = myString.toDouble()
This returns an optional Double?
which has to be unwrapped.
Either with forced unwrapping:
println("The value is \(myDouble!)") // prints: The value is 4.2
or with an if let statement:
if let myDouble = myDouble {
println("The value is \(myDouble)") // prints: The value is 4.2
}
Update: For localization, it is very easy to apply locales to the NSFormatter as follows:
let formatter = NSNumberFormatter()
formatter.locale = NSLocale(localeIdentifier: "fr_FR")
let double = formatter.numberFromString("100,25")
Finally, you can use NSNumberFormatterCurrencyStyle
on the formatter if you are working with currencies where the string contains the currency symbol.
Another option here is converting this to an NSString
and using that:
let string = NSString(string: mySwiftString)
string.doubleValue
Here's an extension method that allows you to simply call doubleValue() on a Swift string and get a double back (example output comes first)
println("543.29".doubleValue())
println("543".doubleValue())
println(".29".doubleValue())
println("0.29".doubleValue())
println("-543.29".doubleValue())
println("-543".doubleValue())
println("-.29".doubleValue())
println("-0.29".doubleValue())
//prints
543.29
543.0
0.29
0.29
-543.29
-543.0
-0.29
-0.29
Here's the extension method:
extension String {
func doubleValue() -> Double
{
let minusAscii: UInt8 = 45
let dotAscii: UInt8 = 46
let zeroAscii: UInt8 = 48
var res = 0.0
let ascii = self.utf8
var whole = [Double]()
var current = ascii.startIndex
let negative = current != ascii.endIndex && ascii[current] == minusAscii
if (negative)
{
current = current.successor()
}
while current != ascii.endIndex && ascii[current] != dotAscii
{
whole.append(Double(ascii[current] - zeroAscii))
current = current.successor()
}
//whole number
var factor: Double = 1
for var i = countElements(whole) - 1; i >= 0; i--
{
res += Double(whole[i]) * factor
factor *= 10
}
//mantissa
if current != ascii.endIndex
{
factor = 0.1
current = current.successor()
while current != ascii.endIndex
{
res += Double(ascii[current] - zeroAscii) * factor
factor *= 0.1
current = current.successor()
}
}
if (negative)
{
res *= -1;
}
return res
}
}
No error checking, but you can add it if you need it.