Fighting NSNumberFormatter in Swift for Currency

I am creating a budget application that allows the user to enter their budget, as well as transactions. I need to allow the user to enter both pensions and kilograms from separate text fields, and they need to be formatted along with currency symbols. I am working fine at the moment, but I want to make it localized as it currently only works with GBP. I tried my best to hide the NSNumberFormatter examples from Objective-C to Swift.

My first problem is that I need to set placeholders for input fields for a specific user location. For example. Pounds and pence, dollars and cents, etc.

The second problem is that the values ​​entered in each of the text fields, such as 10216 and 32, must be formatted and you need to add a currency symbol that is specific to the location of users. Thus, it will become £ 10,216.32 or $ 10,216.32, etc.

In addition, I need to use the result of a formatted number in the calculation. So, how can I do this without running into problems, without running into problems with the currency symbol?

Any help would be greatly appreciated.

+75
swift nsnumberformatter
Jul 25 '14 at 16:47
source share
10 answers

Here is an example of how to use it in Swift 3. ( Edit : works in Swift 4)

let price = 123.436 as NSNumber let formatter = NumberFormatter() formatter.numberStyle = .currency // formatter.locale = NSLocale.currentLocale() // This is the default // In Swift 4, this ^ has been renamed to simply NSLocale.current formatter.string(from: price) // "$123.44" formatter.locale = Locale(identifier: "es_CL") formatter.string(from: price) // $123" formatter.locale = Locale(identifier: "es_ES") formatter.string(from: price) // "123,44 €" 



Here is an old example of how to use it in Swift 2.

 let price = 123.436 let formatter = NSNumberFormatter() formatter.numberStyle = .CurrencyStyle // formatter.locale = NSLocale.currentLocale() // This is the default formatter.stringFromNumber(price) // "$123.44" formatter.locale = NSLocale(localeIdentifier: "es_CL") formatter.stringFromNumber(price) // $123" formatter.locale = NSLocale(localeIdentifier: "es_ES") formatter.stringFromNumber(price) // "123,44 €" 
+186
Jul 25 '14 at 17:00
source share

Swift 3:

If you are looking for a solution that gives you:

  • "5" = "$ 5"
  • "5.0" = "$ 5"
  • "5.00" = "$ 5"
  • "5.5" = "$ 5.50"
  • "5.50" = "$ 5.50"
  • "5.55" = "$ 5.55"
  • "5.234234" = "5.23"

Please use the following:

 func cleanDollars(_ value: String?) -> String { guard value != nil else { return "$0.00" } let doubleValue = Double(value!) ?? 0.0 let formatter = NumberFormatter() formatter.currencyCode = "USD" formatter.currencySymbol = "$" formatter.minimumFractionDigits = (value!.contains(".00")) ? 0 : 2 formatter.maximumFractionDigits = 2 formatter.numberStyle = .currencyAccounting return formatter.string(from: NSNumber(value: doubleValue)) ?? "$\(doubleValue)" } 
+20
Dec 08 '16 at 23:39
source share

I also implemented the solution provided by @ NiñoScript as an extension:

Extension

 // Create a string with currency formatting based on the device locale // extension Float { var asLocaleCurrency:String { var formatter = NSNumberFormatter() formatter.numberStyle = .CurrencyStyle formatter.locale = NSLocale.currentLocale() return formatter.stringFromNumber(self)! } } 

Application:

 let amount = 100.07 let amountString = amount.asLocaleCurrency print(amount.asLocaleCurrency()) // prints: "$100.07" 

Swift 3

  extension Float { var asLocaleCurrency:String { var formatter = NumberFormatter() formatter.numberStyle = .currency formatter.locale = Locale.current return formatter.string(from: self)! } } 
+19
Apr 24 '15 at 16:30
source share

Xcode 9 • Swift 4

 extension Locale { static let br = Locale(identifier: "pt_BR") static let us = Locale(identifier: "en_US") static let uk = Locale(identifier: "en_UK") } 



 extension NumberFormatter { convenience init(style: Style, locale: Locale = .current) { self.init() self.locale = locale numberStyle = style } } 



 extension Formatter { static let currency = NumberFormatter(style: .currency) static let currencyUS = NumberFormatter(style: .currency, locale: .us) static let currencyBR = NumberFormatter(style: .currency, locale: .br) } 



 extension Numeric { // for Swift 3 use FloatingPoint or Int var currency: String { return Formatter.currency.string(for: self) ?? "" } var currencyUS: String { return Formatter.currencyUS.string(for: self) ?? "" } var currencyBR: String { return Formatter.currencyBR.string(for: self) ?? "" } } 



 let price = 1.99 print(Formatter.currency.locale) // "en_US (current)\n" print(price.currency) // "$1.99\n" Formatter.currency.locale = .br print(price.currency) // "R$1,99\n" Formatter.currency.locale = .uk print(price.currency) // "£1.99\n" print(price.currencyBR) // "R$1,99\n" print(price.currencyUS) // "$1.99\n" 
+13
Mar 22 '17 at 16:10
source share

the details

  • Xcode 10.2.1 (10E1001), Swift 5

Decision

 import Foundation class CurrencyFormatter { static var outputFormatter = CurrencyFormatter.create() class func create(locale: Locale = Locale.current, groupingSeparator: String? = nil, decimalSeparator: String? = nil, style: NumberFormatter.Style = NumberFormatter.Style.currency) -> NumberFormatter { let outputFormatter = NumberFormatter() outputFormatter.locale = locale outputFormatter.decimalSeparator = decimalSeparator ?? locale.decimalSeparator outputFormatter.groupingSeparator = groupingSeparator ?? locale.groupingSeparator outputFormatter.numberStyle = style return outputFormatter } } extension Numeric { func toCurrency(formatter: NumberFormatter = CurrencyFormatter.outputFormatter) -> String? { guard let num = self as? NSNumber else { return nil } var formatedSting = formatter.string(from: num) guard let locale = formatter.locale else { return formatedSting } if let separator = formatter.groupingSeparator, let localeValue = locale.groupingSeparator { formatedSting = formatedSting?.replacingOccurrences(of: localeValue, with: separator) } if let separator = formatter.decimalSeparator, let localeValue = locale.decimalSeparator { formatedSting = formatedSting?.replacingOccurrences(of: localeValue, with: separator) } return formatedSting } } 

using

 let price = 12423.42 print(price.toCurrency() ?? "") CurrencyFormatter.outputFormatter = CurrencyFormatter.create(style: .currencyISOCode) print(price.toCurrency() ?? "nil") CurrencyFormatter.outputFormatter = CurrencyFormatter.create(locale: Locale(identifier: "es_ES")) print(price.toCurrency() ?? "nil") CurrencyFormatter.outputFormatter = CurrencyFormatter.create(locale: Locale(identifier: "de_DE"), groupingSeparator: " ", style: .currencyISOCode) print(price.toCurrency() ?? "nil") CurrencyFormatter.outputFormatter = CurrencyFormatter.create(groupingSeparator: "_", decimalSeparator: ".", style: .currencyPlural) print(price.toCurrency() ?? "nil") let formatter = CurrencyFormatter.create(locale: Locale(identifier: "de_DE"), groupingSeparator: " ", decimalSeparator: ",", style: .currencyPlural) print(price.toCurrency(formatter: formatter) ?? "nil") 

results

 $12,423.42 USD12,423.42 12.423,42 € 12 423,42 EUR 12_423.42 US dollars 12 423,42 Euro 
+5
Dec 08 '17 at 15:36
source share

Updated for Swift 4 by @Michael Voccola:

 extension Double { var asLocaleCurrency: String { let formatter = NumberFormatter() formatter.numberStyle = .currency formatter.locale = Locale.current let formattedString = formatter.string(from: self as NSNumber) return formattedString ?? "" } } 

Note: there are no forced deployments, no forced deployments are evil.

+2
Feb 05 '19 at 16:31
source share

Swift 4 TextField implemented

 var value = 0 currencyTextField.delegate = self func numberFormatting(money: Int) -> String { let formatter = NumberFormatter() formatter.numberStyle = .currency formatter.locale = .current return formatter.string(from: money as NSNumber)! } currencyTextField.text = formatter.string(from: 50 as NSNumber)! func textFieldDidEndEditing(_ textField: UITextField) { value = textField.text textField.text = numberFormatting(money: Int(textField.text!) ?? 0 as! Int) } func textFieldDidBeginEditing(_ textField: UITextField) { textField.text = value } 
+1
Feb 12 '19 at 9:13
source share

Swift 4

 formatter.locale = Locale.current 

if you want to change the locale you can do it like this

 formatter.locale = Locale.init(identifier: "id-ID") 

// This is the locale for Indonesia. if you want to use according to the area of ​​the mobile phone, use it according to the upper mention Locale.current

 //MARK:- Complete code let formatter = NumberFormatter() formatter.numberStyle = .currency if let formattedTipAmount = formatter.string(from: Int(newString)! as NSNumber) { yourtextfield.text = formattedTipAmount } 
0
Apr 16 '18 at 8:02
source share

add this function

 func addSeparateMarkForNumber(int: Int) -> String { var string = "" let formatter = NumberFormatter() formatter.locale = Locale.current formatter.numberStyle = .decimal if let formattedTipAmount = formatter.string(from: int as NSNumber) { string = formattedTipAmount } return string } 

via:

 let giaTri = value as! Int myGuessTotalCorrect = addSeparateMarkForNumber(int: giaTri) 
0
May 13 '18 at 10:41
source share
 extension Float { var convertAsLocaleCurrency :String { var formatter = NumberFormatter() formatter.numberStyle = .currency formatter.locale = Locale.current return formatter.string(from: self as NSNumber)! } } 

This works for fast 3.1 xcode 8.2.1

-one
Mar 01 '17 at 8:52
source share



All Articles