Swift: how to remove a special character from a string? - swift

I want to remove the special character , in a string so I can convert the value to a double. How do I do it?
Example:
let stringValue = "4,000.50";
I have tried to use the NumberFormatter but getting nil error
let NF = NumberFormatter();
let value = NF.number(from: stringValue);
//nil

If the number string will always be formatted from a specific locale then you need to set the formatter's locale to match. Without setting the locale, the string won't be parsed if the user's locale using different grouping and decimal formatting.
let stringValue = "4,000.50"
let nf = NumberFormatter()
nf.numberStyle = .decimal
nf.locale = Locale(identifier: "en_US")
let value = nf.number(from: stringValue)
FYI - this is Swift, you don't need semicolons at the end of lines.

Same as #rmaddy but using string replacingOccurrences :
var stringValue = "4,000,000.50"
stringValue = stringValue.replacingOccurrences(of: ",", with: "")
let nf = NumberFormatter()
let value = nf.number(from: stringValue)
print(value)

If you know you're working with currency, you could clean-up the text value for any decimal and thousand separator by leveraging the pattern of consecutive digits. If there are any decimals, they would be the last group and would have exactly two digits (for most currencies). On the basis of this assumption, you don't need to know which separator is used and you would also be resilient to the presence of other characters such as the currency name or symbol:
let textValue = "Balance : 1 200,33 Euros"
let nonDigits = CharacterSet(charactersIn: "01234456789").inverted
let digitGroups = textValue.components(separatedBy:nonDigits).filter{!$0.isEmpty}
let textNumber = digitGroups.dropLast().joined(separator:"")
+ ( digitGroups.last!.characters.count == 2
&& digitGroups.count > 1 ? "." : "" )
+ digitGroups.last!
textNumber // 1200.33

If you just want a sanitized string with only digits and decimals, then in Xcode 9.0+ you can just do:
let originalString = "4,000.00"
let numberString = originalString.filter({ "1234567890.".contains($0) })
// numberString -> "4000.00"
Then, converting your sanitized string to a Float is as easy as
if let num = Float(numberString) {
// do something with float
} else {
// failed to init float with string
}

Related

Swift lose precision in decimal formatting

I have an precision issue when dealing with currency input using Decimal type. The issue is with the formatter. This is the minimum reproducible code in playground:
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.isLenient = true
formatter.maximumFractionDigits = 2
formatter.generatesDecimalNumbers = true
let text = "89806.9"
let decimal = formatter.number(from: text)?.decimalValue ?? .zero
let string = "\(decimal)"
print(string)
It prints out 89806.89999999999 instead of 89806.9. However, most other numbers are fine (e.g. 8980.9). So I don't think this is a Double vs Decimal problem.
Edit:
The reason I need to use the formatter is that sometimes I need to deal with currency format input:
let text = "$89,806.9"
let decimal = formatter.number(from: text)?.decimalValue ?? .zero
print("\(decimal)") // prints 89806.89999999999
let text2 = "$89,806.9"
let decimal2 = Decimal(string: text2)
print("\(decimal2)") // prints nil
Using the new FormatStyle seems to generate the correct result
let format = Decimal.FormatStyle
.number
.precision(.fractionLength(0...2))
let text = "89806.9"
let value = try! format.parseStrategy.parse(text)
Below is an example parsing a currency using the currency code from the locale
let currencyFormat = Decimal.FormatStyle.Currency
.currency(code: Locale.current.currencyCode!)
.precision(.fractionLength(0...2))
let amount = try! currencyFormat.parseStrategy.parse(text)
Swedish example:
let text = "89806,9 kr"
print(amount)
89806.9
Another option is to use the new init for Decimal that takes a String and a FormatStyle.Currency (or a Number or Percent)
let amount = try Decimal(text, format: currencyFormat)
and to format this value we can use formatted(_:) on Decimal
print(amount.formatted(currencyFormat))
Output (still Swedish):
89 806,9 kr
I agree that this is a surprising bug, and I would open an Apple Feedback about it, but I would also highly recommend switching to Decimal(string:locale:) rather than a formatter, which will achieve your goal (except perhaps the isLenient part).
let x = Decimal(string: text)!
print("\(x)") // 89806.9
If you want to fix fraction digits, you can apply rounding pretty easily with * 100 / 100 conversions through Int. (I'll explain if it's not obvious how to do this; it works for Decimal, though not Double.)
Following Joakim Danielson Answer see this amazing documentation on the format style
Decimal(10.01).formatted(.number.precision(.fractionLength(1))) // 10.0 Decimal(10.01).formatted(.number.precision(.fractionLength(2))) // 10.01 Decimal(10.01).formatted(.number.precision(.fractionLength(3))) // 10.010
Amazingly detailed documentation
If this is strictly a rendering issue and you're just looking to translate a currency value from raw string to formatted string then just do that.
let formatter = NumberFormatter()
formatter.numberStyle = .currency
let raw = "89806.9"
if let double = Double(raw),
let currency = formatter.string(from: NSNumber(value: double)) {
print(currency) // $89,806.90
}
If there is math involved then before you get to the use of string formatters, I would point you to
Why not use Double or Float to represent currency? and
How to round a double to an int using Banker's Rounding in C as great starting points.
I get my response with double value and remove formatter.generatesDecimalNumbers line to get work.
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.isLenient = true
formatter.maximumFractionDigits = 2
//formatter.generatesDecimalNumbers = true // I removed this line
let text = "$89806.9"
let double = formatter.number(from: text)?.doubleValue ?? .zero // converting as double or float
let string = "\(double)"
print(string) // 89806.9
let anotherText = "$0.1"
let anotherDouble = formatter.number(from: anotherText)?.doubleValue ?? .zero // converting as double or float
let anotherString = "\(anotherDouble)"
print(anotherString) // 0.1

Swift String to Int Always Returns nil

I am trying to convert a String to an Int. Seems simple enough, but for somer reason it is always returning nil.
I'm just writing a simple extension to convert dollars to cents:
func dollarsToCents() -> Int {
var temp = self;
temp = temp.replacingOccurrences(of: "$", with: "")
temp = temp.replacingOccurrences(of: ",", with: "")
if let number = Int(temp) {
return number*100
}
return 0
}
I have temp set to "$250.89". number is always nil. No matter how I approach converting temp to an Int it is always nil. Anyone know what I'm doing wrong?
Problem is, that string "250.89" (after removing currency symbol) can't be converted to Int because 250.89 isn't integer. So fix your code by converting it to Double
func dollarsToCents() -> Int {
var temp = self
temp.removeAll { "$,".contains($0) }
//temp = temp.replacingOccurrences(of: "[$,]", with: "", options: .regularExpression)
return Int(((Double(temp) ?? 0) * 100).rounded())
}
or if your "number" always have two decimal places
func dollarsToCents() -> Int {
var temp = self
temp.removeAll { !("0"..."9" ~= $0) }
return Int(temp) ?? 0
}
But I think solution is much easier. Your goal should be saving price value as number (Double,...). Then you don't have to convert String to Double and you can just multiply your number. Then when you need to add currency symbol, just convert your value to String and add $ or use NumberFormatter
let price = 250.89
let formattedPrice = "$\(price)" // $250.89
let price = 250.89
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencyCode = "USD"
let formattedPrice = formatter.string(from: price as NSNumber)! // $250.89
Just adding this for the bizarre edge-case that I just encountered - be sure there aren't any whitespaces either trailing or leading in your string when converting to Int from String.
Eg.
for date in next_thirty_days {
let date_buffer: String = date.description[8...9]
date_list.append(Int(date_buffer)!)
}
This will fail if the value for date_buffer has a leading or trailing white-space.
Another edge-case is that there's a leading 0 in the string variable, eg. 07.
Hope it helps :)

Convert the text from a String to a Double [duplicate]

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.
As of Swift 1.1, you can directly pass String to const char * parameter.
import Foundation
let str = "123.4567"
let num = atof(str) // -> 123.4567
atof("123.4567fubar") // -> 123.4567
If you don't like deprecated atof:
strtod("765.4321", nil) // -> 765.4321
One caveat: the behavior of conversion is different from NSString.doubleValue.
atof and strtod accept 0x prefixed hex string:
atof("0xffp-2") // -> 63.75
atof("12.3456e+2") // -> 1,234.56
atof("nan") // -> (not a number)
atof("inf") // -> (+infinity)
If you prefer .doubleValue behavior, we can still use CFString bridging:
let str = "0xff"
atof(str) // -> 255.0
strtod(str, nil) // -> 255.0
CFStringGetDoubleValue(str) // -> 0.0
(str as NSString).doubleValue // -> 0.0
I haven't seen the answer I was looking for.
I just post in here mine in case it can help anyone. This answer is valid only if you don't need a specific format.
Swift 3
extension String {
var toDouble: Double {
return Double(self) ?? 0.0
}
}
In Swift 2.0 the best way is to avoid thinking like an Objective-C developer. So you should not "convert a String to a Double" but you should "initialize a Double from a String". Apple doc over here:
https://developer.apple.com/library/ios//documentation/Swift/Reference/Swift_Double_Structure/index.html#//apple_ref/swift/structctr/Double/s:FSdcFMSdFSSGSqSd_
It's an optional init so you can use the nil coalescing operator (??) to set a default value. Example:
let myDouble = Double("1.1") ?? 0.0
On SWIFT 3, you can use:
if let myDouble = NumberFormatter().number(from: yourString)?.doubleValue {
print("My double: \(myDouble)")
}
Note:
- If a string contains any characters other than numerical digits or locale-appropriate group or decimal separators, parsing will fail.
- Any leading or trailing space separator characters in a string are ignored. For example, the strings “ 5”, “5 ”, and “5” all produce the number 5.
Taken from the documentation:
https://developer.apple.com/reference/foundation/numberformatter/1408845-number
Try this:
var myDouble = myString.bridgeToObjectiveC().doubleValue
println(myDouble)
NOTE
Removed in Beta 5. This no longer works ?
This is building upon the answer by #Ryu
His solution is great as long as you're in a country where dots are used as separators. By default NSNumberFormatter uses the devices locale. Therefore this will fail in all countries where a comma is used as the default separator (including France as #PeterK. mentioned) if the number uses dots as separators (which is normally the case). To set the locale of this NSNumberFormatter to be US and thus use dots as separators replace the line
return NSNumberFormatter().numberFromString(self)?.doubleValue
with
let numberFormatter = NSNumberFormatter()
numberFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
return numberFormatter.numberFromString(self)?.doubleValue
Therefore the full code becomes
extension String {
func toDouble() -> Double? {
let numberFormatter = NSNumberFormatter()
numberFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
return numberFormatter.numberFromString(self)?.doubleValue
}
}
To use this, just call "Your text goes here".toDouble()
This will return an optional Double?
As #Ryu mentioned you can either force unwrap:
println("The value is \(myDouble!)") // prints: The value is 4.2
or use an if let statement:
if let myDouble = myDouble {
println("The value is \(myDouble)") // prints: The value is 4.2
}
SWIFT 4
extension String {
func toDouble() -> Double? {
let numberFormatter = NumberFormatter()
numberFormatter.locale = Locale(identifier: "en_US_POSIX")
return numberFormatter.number(from: self)?.doubleValue
}
}
Swift 4.0
try this
let str:String = "111.11"
let tempString = (str as NSString).doubleValue
print("String:-",tempString)
Swift : 4 and 5
There are possibly two ways to do this:
String -> Int -> Double:
let strNumber = "314"
if let intFromString = Int(strNumber){
let dobleFromInt = Double(intFromString)
print(dobleFromInt)
}
String -> NSString -> Double
let strNumber1 = "314"
let NSstringFromString = NSString(string: strNumber1)
let doubleFromNSString = NSstringFromString.doubleValue
print(doubleFromNSString)
Use it anyway you like according to you need of the code.
Please check it on playground!
let sString = "236.86"
var dNumber = NSNumberFormatter().numberFromString(sString)
var nDouble = dNumber!
var eNumber = Double(nDouble) * 3.7
By the way in my Xcode
.toDouble() - doesn't exist
.doubleValue create value 0.0 from not numerical strings...
As already pointed out, the best way to achieve this is with direct casting:
(myString as NSString).doubleValue
Building from that, you can make a slick native Swift String extension:
extension String {
var doubleValue: Double {
return (self as NSString).doubleValue
}
}
This allows you to directly use:
myString.doubleValue
Which will perform the casting for you. If Apple does add a doubleValue to the native String you just need to remove the extension and the rest of your code will automatically compile fine!
1.
let strswift = "12"
let double = (strswift as NSString).doubleValue
2.
var strswift= "10.6"
var double : Double = NSString(string: strswift).doubleValue
May be this help for you.
Extension with optional locale
Swift 2.2
extension String {
func toDouble(locale: NSLocale? = nil) -> Double? {
let formatter = NSNumberFormatter()
if let locale = locale {
formatter.locale = locale
}
return formatter.numberFromString(self)?.doubleValue
}
}
Swift 3.1
extension String {
func toDouble(_ locale: Locale) -> Double {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = locale
formatter.usesGroupingSeparator = true
if let result = formatter.number(from: self)?.doubleValue {
return result
} else {
return 0
}
}
}
SWIFT 3
To clear, nowadays there is a default method:
public init?(_ text: String)` of `Double` class.
It can be used for all classes.
let c = Double("-1.0")
let f = Double("0x1c.6")
let i = Double("inf")
, etc.
Or you could do:
var myDouble = Double((mySwiftString.text as NSString).doubleValue)
You can use StringEx. It extends String with string-to-number conversions including toDouble().
extension String {
func toDouble() -> Double?
}
It verifies the string and fails if it can't be converted to double.
Example:
import StringEx
let str = "123.45678"
if let num = str.toDouble() {
println("Number: \(num)")
} else {
println("Invalid string")
}
Swift 4
extension String {
func toDouble() -> Double {
let nsString = self as NSString
return nsString.doubleValue
}
}
What also works:
// Init default Double variable
var scanned: Double()
let scanner = NSScanner(string: "String to Scan")
scanner.scanDouble(&scanned)
// scanned has now the scanned value if something was found.
Using Scanner in some cases is a very convenient way of extracting numbers from a string. And it is almost as powerful as NumberFormatter when it comes to decoding and dealing with different number formats and locales. It can extract numbers and currencies with different decimal and group separators.
import Foundation
// The code below includes manual fix for whitespaces (for French case)
let strings = ["en_US": "My salary is $9,999.99",
"fr_FR": "Mon salaire est 9 999,99€",
"de_DE": "Mein Gehalt ist 9999,99€",
"en_GB": "My salary is £9,999.99" ]
// Just for referce
let allPossibleDecimalSeparators = Set(Locale.availableIdentifiers.compactMap({ Locale(identifier: $0).decimalSeparator}))
print(allPossibleDecimalSeparators)
for str in strings {
let locale = Locale(identifier: str.key)
let valStr = str.value.filter{!($0.isWhitespace || $0 == Character(locale.groupingSeparator ?? ""))}
print("Value String", valStr)
let sc = Scanner(string: valStr)
// we could do this more reliably with `filter` as well
sc.charactersToBeSkipped = CharacterSet.decimalDigits.inverted
sc.locale = locale
print("Locale \(locale.identifier) grouping separator: |\(locale.groupingSeparator ?? "")| . Decimal separator: \(locale.decimalSeparator ?? "")")
while !(sc.isAtEnd) {
if let val = sc.scanDouble() {
print(val)
}
}
}
However, there are issues with separators that could be conceived as word delimiters.
// This doesn't work. `Scanner` just ignores grouping separators because scanner tends to seek for multiple values
// It just refuses to ignore spaces or commas for example.
let strings = ["en_US": "$9,999.99", "fr_FR": "9999,99€", "de_DE": "9999,99€", "en_GB": "£9,999.99" ]
for str in strings {
let locale = Locale(identifier: str.key)
let sc = Scanner(string: str.value)
sc.charactersToBeSkipped = CharacterSet.decimalDigits.inverted.union(CharacterSet(charactersIn: locale.groupingSeparator ?? ""))
sc.locale = locale
print("Locale \(locale.identifier) grouping separator: \(locale.groupingSeparator ?? "") . Decimal separator: \(locale.decimalSeparator ?? "")")
while !(sc.isAtEnd) {
if let val = sc.scanDouble() {
print(val)
}
}
}
// sc.scanDouble(representation: Scanner.NumberRepresentation) could help if there were .currency case
There is no problem to auto detect locale. Note that groupingSeparator in French locale in string "Mon salaire est 9 999,99€" is not a space, though it may render exactly as space (here it doesn't). Thats why the code below works fine without !$0.isWhitespace characters being filtered out.
let stringsArr = ["My salary is $9,999.99",
"Mon salaire est 9 999,99€",
"Mein Gehalt ist 9.999,99€",
"My salary is £9,999.99" ]
let tagger = NSLinguisticTagger(tagSchemes: [.language], options: Int(NSLinguisticTagger.Options.init().rawValue))
for str in stringsArr {
tagger.string = str
let locale = Locale(identifier: tagger.dominantLanguage ?? "en")
let valStr = str.filter{!($0 == Character(locale.groupingSeparator ?? ""))}
print("Value String", valStr)
let sc = Scanner(string: valStr)
// we could do this more reliably with `filter` as well
sc.charactersToBeSkipped = CharacterSet.decimalDigits.inverted
sc.locale = locale
print("Locale \(locale.identifier) grouping separator: |\(locale.groupingSeparator ?? "")| . Decimal separator: \(locale.decimalSeparator ?? "")")
while !(sc.isAtEnd) {
if let val = sc.scanDouble() {
print(val)
}
}
}
// Also will fail if groupingSeparator == decimalSeparator (but don't think it's possible)
Use this code in Swift 2.0
let strWithFloat = "78.65"
let floatFromString = Double(strWithFloat)
In the cases of strings contain other characters like: "27.8 °C", "52.523553 kM" or "Total: 349.0".
This works in Swift 4:
let anyString = "52.523553 kM"
let digitsCharacterSet = CharacterSet.init(charactersIn: "0123456789.")
let doubleResult = Double(anyString.components(separatedBy:digitsCharacterSet.inverted).joined())
Caution! This not working for strings contain multiple . like "27.8 °C 3.5 kM"
I find more readable to add an extension to String as follow:
extension String {
var doubleValue: Double {
return (self as NSString).doubleValue
}
}
and then you just could write your code:
myDouble = myString.doubleValue
my problem was comma so i solve it this way:
extension String {
var doubleValue: Double {
return Double((self.replacingOccurrences(of: ",", with: ".") as NSString).doubleValue)
}
}
var stringValue = "55"
var convertToDouble = Double((stringValue as NSString).doubleValue)
we can use CDouble value which will be obtained by myString.doubleValue

Elegant way of stripping string of currency characters?

Currently Im receiving a string from a service that contains currency characters (Ex. "$123.44", "123,44 €"). I would like to strip these stings of their currency characters in order to perform some calculations on these prices (adding money, subtracting money...etc).
I know I could replace occurrences of certain characters and then re-add them later after the calculations, but I get the impression that there might be a better solution out there.
Any ideas?
You can use NSNumberFormatter to convert a formatted price into a Double value
func getNumber(formattedPrice: String, localeID: String) -> Double? {
let formatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
formatter.locale = NSLocale(localeIdentifier: localeID)
return formatter.numberFromString(formattedPrice)?.doubleValue
}
but you'll need to specify the locale
getNumber("$123.44", localeID: "en_US") // 123.44
getNumber("123,44€", localeID: "it_IT") // 123.44
getNumber("£123.44", localeID: "en_UK") // 123.44
You can use an NSCharacterSet to root out those characters, like this:
var dollarStr = "$1.50"
var yuanStr = "¥18.25"
var euroStr = "20.75 €"
let strArray = [dollarStr, yuanStr, euroStr]
let charSet = NSCharacterSet(charactersInString: "$¥€ ")
for str in strArray {
let trimmedStr = str.stringByTrimmingCharactersInSet(charSet)
print(trimmedStr)
}
prints out :
1.50
18.25
20.75

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.
As of Swift 1.1, you can directly pass String to const char * parameter.
import Foundation
let str = "123.4567"
let num = atof(str) // -> 123.4567
atof("123.4567fubar") // -> 123.4567
If you don't like deprecated atof:
strtod("765.4321", nil) // -> 765.4321
One caveat: the behavior of conversion is different from NSString.doubleValue.
atof and strtod accept 0x prefixed hex string:
atof("0xffp-2") // -> 63.75
atof("12.3456e+2") // -> 1,234.56
atof("nan") // -> (not a number)
atof("inf") // -> (+infinity)
If you prefer .doubleValue behavior, we can still use CFString bridging:
let str = "0xff"
atof(str) // -> 255.0
strtod(str, nil) // -> 255.0
CFStringGetDoubleValue(str) // -> 0.0
(str as NSString).doubleValue // -> 0.0
I haven't seen the answer I was looking for.
I just post in here mine in case it can help anyone. This answer is valid only if you don't need a specific format.
Swift 3
extension String {
var toDouble: Double {
return Double(self) ?? 0.0
}
}
In Swift 2.0 the best way is to avoid thinking like an Objective-C developer. So you should not "convert a String to a Double" but you should "initialize a Double from a String". Apple doc over here:
https://developer.apple.com/library/ios//documentation/Swift/Reference/Swift_Double_Structure/index.html#//apple_ref/swift/structctr/Double/s:FSdcFMSdFSSGSqSd_
It's an optional init so you can use the nil coalescing operator (??) to set a default value. Example:
let myDouble = Double("1.1") ?? 0.0
On SWIFT 3, you can use:
if let myDouble = NumberFormatter().number(from: yourString)?.doubleValue {
print("My double: \(myDouble)")
}
Note:
- If a string contains any characters other than numerical digits or locale-appropriate group or decimal separators, parsing will fail.
- Any leading or trailing space separator characters in a string are ignored. For example, the strings “ 5”, “5 ”, and “5” all produce the number 5.
Taken from the documentation:
https://developer.apple.com/reference/foundation/numberformatter/1408845-number
Try this:
var myDouble = myString.bridgeToObjectiveC().doubleValue
println(myDouble)
NOTE
Removed in Beta 5. This no longer works ?
This is building upon the answer by #Ryu
His solution is great as long as you're in a country where dots are used as separators. By default NSNumberFormatter uses the devices locale. Therefore this will fail in all countries where a comma is used as the default separator (including France as #PeterK. mentioned) if the number uses dots as separators (which is normally the case). To set the locale of this NSNumberFormatter to be US and thus use dots as separators replace the line
return NSNumberFormatter().numberFromString(self)?.doubleValue
with
let numberFormatter = NSNumberFormatter()
numberFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
return numberFormatter.numberFromString(self)?.doubleValue
Therefore the full code becomes
extension String {
func toDouble() -> Double? {
let numberFormatter = NSNumberFormatter()
numberFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
return numberFormatter.numberFromString(self)?.doubleValue
}
}
To use this, just call "Your text goes here".toDouble()
This will return an optional Double?
As #Ryu mentioned you can either force unwrap:
println("The value is \(myDouble!)") // prints: The value is 4.2
or use an if let statement:
if let myDouble = myDouble {
println("The value is \(myDouble)") // prints: The value is 4.2
}
SWIFT 4
extension String {
func toDouble() -> Double? {
let numberFormatter = NumberFormatter()
numberFormatter.locale = Locale(identifier: "en_US_POSIX")
return numberFormatter.number(from: self)?.doubleValue
}
}
Swift 4.0
try this
let str:String = "111.11"
let tempString = (str as NSString).doubleValue
print("String:-",tempString)
Swift : 4 and 5
There are possibly two ways to do this:
String -> Int -> Double:
let strNumber = "314"
if let intFromString = Int(strNumber){
let dobleFromInt = Double(intFromString)
print(dobleFromInt)
}
String -> NSString -> Double
let strNumber1 = "314"
let NSstringFromString = NSString(string: strNumber1)
let doubleFromNSString = NSstringFromString.doubleValue
print(doubleFromNSString)
Use it anyway you like according to you need of the code.
Please check it on playground!
let sString = "236.86"
var dNumber = NSNumberFormatter().numberFromString(sString)
var nDouble = dNumber!
var eNumber = Double(nDouble) * 3.7
By the way in my Xcode
.toDouble() - doesn't exist
.doubleValue create value 0.0 from not numerical strings...
As already pointed out, the best way to achieve this is with direct casting:
(myString as NSString).doubleValue
Building from that, you can make a slick native Swift String extension:
extension String {
var doubleValue: Double {
return (self as NSString).doubleValue
}
}
This allows you to directly use:
myString.doubleValue
Which will perform the casting for you. If Apple does add a doubleValue to the native String you just need to remove the extension and the rest of your code will automatically compile fine!
1.
let strswift = "12"
let double = (strswift as NSString).doubleValue
2.
var strswift= "10.6"
var double : Double = NSString(string: strswift).doubleValue
May be this help for you.
Extension with optional locale
Swift 2.2
extension String {
func toDouble(locale: NSLocale? = nil) -> Double? {
let formatter = NSNumberFormatter()
if let locale = locale {
formatter.locale = locale
}
return formatter.numberFromString(self)?.doubleValue
}
}
Swift 3.1
extension String {
func toDouble(_ locale: Locale) -> Double {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = locale
formatter.usesGroupingSeparator = true
if let result = formatter.number(from: self)?.doubleValue {
return result
} else {
return 0
}
}
}
SWIFT 3
To clear, nowadays there is a default method:
public init?(_ text: String)` of `Double` class.
It can be used for all classes.
let c = Double("-1.0")
let f = Double("0x1c.6")
let i = Double("inf")
, etc.
Or you could do:
var myDouble = Double((mySwiftString.text as NSString).doubleValue)
You can use StringEx. It extends String with string-to-number conversions including toDouble().
extension String {
func toDouble() -> Double?
}
It verifies the string and fails if it can't be converted to double.
Example:
import StringEx
let str = "123.45678"
if let num = str.toDouble() {
println("Number: \(num)")
} else {
println("Invalid string")
}
Swift 4
extension String {
func toDouble() -> Double {
let nsString = self as NSString
return nsString.doubleValue
}
}
What also works:
// Init default Double variable
var scanned: Double()
let scanner = NSScanner(string: "String to Scan")
scanner.scanDouble(&scanned)
// scanned has now the scanned value if something was found.
Using Scanner in some cases is a very convenient way of extracting numbers from a string. And it is almost as powerful as NumberFormatter when it comes to decoding and dealing with different number formats and locales. It can extract numbers and currencies with different decimal and group separators.
import Foundation
// The code below includes manual fix for whitespaces (for French case)
let strings = ["en_US": "My salary is $9,999.99",
"fr_FR": "Mon salaire est 9 999,99€",
"de_DE": "Mein Gehalt ist 9999,99€",
"en_GB": "My salary is £9,999.99" ]
// Just for referce
let allPossibleDecimalSeparators = Set(Locale.availableIdentifiers.compactMap({ Locale(identifier: $0).decimalSeparator}))
print(allPossibleDecimalSeparators)
for str in strings {
let locale = Locale(identifier: str.key)
let valStr = str.value.filter{!($0.isWhitespace || $0 == Character(locale.groupingSeparator ?? ""))}
print("Value String", valStr)
let sc = Scanner(string: valStr)
// we could do this more reliably with `filter` as well
sc.charactersToBeSkipped = CharacterSet.decimalDigits.inverted
sc.locale = locale
print("Locale \(locale.identifier) grouping separator: |\(locale.groupingSeparator ?? "")| . Decimal separator: \(locale.decimalSeparator ?? "")")
while !(sc.isAtEnd) {
if let val = sc.scanDouble() {
print(val)
}
}
}
However, there are issues with separators that could be conceived as word delimiters.
// This doesn't work. `Scanner` just ignores grouping separators because scanner tends to seek for multiple values
// It just refuses to ignore spaces or commas for example.
let strings = ["en_US": "$9,999.99", "fr_FR": "9999,99€", "de_DE": "9999,99€", "en_GB": "£9,999.99" ]
for str in strings {
let locale = Locale(identifier: str.key)
let sc = Scanner(string: str.value)
sc.charactersToBeSkipped = CharacterSet.decimalDigits.inverted.union(CharacterSet(charactersIn: locale.groupingSeparator ?? ""))
sc.locale = locale
print("Locale \(locale.identifier) grouping separator: \(locale.groupingSeparator ?? "") . Decimal separator: \(locale.decimalSeparator ?? "")")
while !(sc.isAtEnd) {
if let val = sc.scanDouble() {
print(val)
}
}
}
// sc.scanDouble(representation: Scanner.NumberRepresentation) could help if there were .currency case
There is no problem to auto detect locale. Note that groupingSeparator in French locale in string "Mon salaire est 9 999,99€" is not a space, though it may render exactly as space (here it doesn't). Thats why the code below works fine without !$0.isWhitespace characters being filtered out.
let stringsArr = ["My salary is $9,999.99",
"Mon salaire est 9 999,99€",
"Mein Gehalt ist 9.999,99€",
"My salary is £9,999.99" ]
let tagger = NSLinguisticTagger(tagSchemes: [.language], options: Int(NSLinguisticTagger.Options.init().rawValue))
for str in stringsArr {
tagger.string = str
let locale = Locale(identifier: tagger.dominantLanguage ?? "en")
let valStr = str.filter{!($0 == Character(locale.groupingSeparator ?? ""))}
print("Value String", valStr)
let sc = Scanner(string: valStr)
// we could do this more reliably with `filter` as well
sc.charactersToBeSkipped = CharacterSet.decimalDigits.inverted
sc.locale = locale
print("Locale \(locale.identifier) grouping separator: |\(locale.groupingSeparator ?? "")| . Decimal separator: \(locale.decimalSeparator ?? "")")
while !(sc.isAtEnd) {
if let val = sc.scanDouble() {
print(val)
}
}
}
// Also will fail if groupingSeparator == decimalSeparator (but don't think it's possible)
Use this code in Swift 2.0
let strWithFloat = "78.65"
let floatFromString = Double(strWithFloat)
In the cases of strings contain other characters like: "27.8 °C", "52.523553 kM" or "Total: 349.0".
This works in Swift 4:
let anyString = "52.523553 kM"
let digitsCharacterSet = CharacterSet.init(charactersIn: "0123456789.")
let doubleResult = Double(anyString.components(separatedBy:digitsCharacterSet.inverted).joined())
Caution! This not working for strings contain multiple . like "27.8 °C 3.5 kM"
I find more readable to add an extension to String as follow:
extension String {
var doubleValue: Double {
return (self as NSString).doubleValue
}
}
and then you just could write your code:
myDouble = myString.doubleValue
my problem was comma so i solve it this way:
extension String {
var doubleValue: Double {
return Double((self.replacingOccurrences(of: ",", with: ".") as NSString).doubleValue)
}
}
var stringValue = "55"
var convertToDouble = Double((stringValue as NSString).doubleValue)
we can use CDouble value which will be obtained by myString.doubleValue