Lutando com NSNumberFormatter no Swift por moeda

Estou criando um aplicativo de orçamento que permite ao usuário inserir seu orçamento e transactions. Eu preciso permitir que o usuário insira pence e libras de campos de texto separados e eles precisam ser formatados junto com símbolos de moeda. Eu tenho esta funcionando bem no momento, mas gostaria de torná-lo localizado como atualmente só funciona com GBP. Eu tenho lutado para converter exemplos NSNumberFormatter de Objective C para Swift.

Meu primeiro problema é o fato de que preciso definir os espaços reservados para os campos de input para serem específicos da localização dos usuários. Por exemplo. Libras e Pence, dólares e centavos etc …

A segunda questão é que os valores inseridos em cada um dos campos de texto, como 10216 e 32, precisam ser formatados e o símbolo monetário específico da localização dos usuários precisa ser adicionado. Então, isso se tornaria £ 10.216,32 ou $ 10.216,32 etc …

Além disso, preciso usar o resultado do número formatado em um cálculo. Então, como posso fazer isso sem ter problemas sem ter problemas com o símbolo monetário?

Qualquer ajuda seria muito apreciada.

Aqui está um exemplo de como usá-lo no Swift 3. ( Edit : Works no Swift 4 também)

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 €" 

Aqui está o antigo exemplo de como usá-lo no 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 €" 

Eu implementei a solução fornecida pelo @ NiñoScript como uma extensão:

Extensão

 // 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)! } } 

Uso:

 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)! } } 

Swift 3:

Se você está procurando uma solução que lhe dê:

  • “5” = “$ 5”
  • “5,0” = “$ 5”
  • “5,00” = “US $ 5”
  • “5,5” = “US $ 5,50”
  • “5,50” = “US $ 5,50”
  • “5,55” = “US $ 5,55”
  • “5,234234” = “5,23”

Por favor use o seguinte:

 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)" } 

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" 

Detalhes

xCode 9.2, Swift 4

Solução 1

 import Foundation extension String { var toLocale: Locale { return Locale(identifier: self) } } extension Numeric { func currency(numberStyle: NumberFormatter.Style = NumberFormatter.Style.currency, locale: String, groupingSeparator: String? = nil, decimalSeparator: String? = nil) -> String? { return currency(numberStyle: numberStyle, locale: locale.toLocale, groupingSeparator: groupingSeparator, decimalSeparator: decimalSeparator) } func currency(numberStyle: NumberFormatter.Style = NumberFormatter.Style.currency, locale: Locale = Locale.current, groupingSeparator: String? = nil, decimalSeparator: String? = nil) -> String? { if let num = self as? NSNumber { let formater = NumberFormatter() formater.locale = locale formater.numberStyle = numberStyle var formatedSting = formater.string(from: num) if let separator = groupingSeparator, let localeValue = locale.groupingSeparator { formatedSting = formatedSting?.replacingOccurrences(of: localeValue, with: separator) } if let separator = decimalSeparator, let localeValue = locale.decimalSeparator { formatedSting = formatedSting?.replacingOccurrences(of: localeValue, with: separator) } return formatedSting } return nil } } 

Uso

 let price = 12423.42 print(price.currency() ?? "nil") print(price.currency(numberStyle: .currencyISOCode) ?? "nil") print(price.currency(locale: "es_ES") ?? "nil") print(price.currency(locale: "es_ES", groupingSeparator: "_", decimalSeparator: ".") ?? "nil") 

Resultado

insira a descrição da imagem aqui

Solução 2

 import Foundation extension String { var toLocale: Locale { return Locale(identifier: self) } } class NumFormatter { static var shared = NumFormatter() public private(set) var formater = NumberFormatter() public private(set) var groupingSeparator: String? = nil public private(set) var decimalSeparator: String? = nil public var locale: Locale { return formater.locale } class func locale(string: String) -> NumFormatter.Type { NumFormatter.shared.formater.locale = string.toLocale return NumFormatter.self } class func number(style: NumberFormatter.Style = NumberFormatter.Style.currency) -> NumFormatter.Type { NumFormatter.shared.formater.numberStyle = style return NumFormatter.self } class func number(groupingSeparator: String?) -> NumFormatter.Type { NumFormatter.shared.groupingSeparator = groupingSeparator return NumFormatter.self } class func number(decimalSeparator: String?) -> NumFormatter.Type { NumFormatter.shared.decimalSeparator = decimalSeparator return NumFormatter.self } } extension Numeric { func currency() -> String? { if let num = self as? NSNumber { let formater = NumFormatter.shared.formater var formatedSting = formater.string(from: num) if let separator = NumFormatter.shared.groupingSeparator, let localeValue = formater.locale.groupingSeparator { formatedSting = formatedSting?.replacingOccurrences(of: localeValue, with: separator) } if let separator = NumFormatter.shared.decimalSeparator, let localeValue = formater.locale.decimalSeparator { formatedSting = formatedSting?.replacingOccurrences(of: localeValue, with: separator) } return formatedSting } return nil } } 

Uso

 let price = 12423.42 print(price.currency() ?? "nil") NumFormatter.number(style: .currencyISOCode) print(price.currency() ?? "nil") NumFormatter.locale(string: "es_ES") print(price.currency() ?? "nil") NumFormatter.number(groupingSeparator: "_").number(decimalSeparator: ".") print(price.currency() ?? "nil") 

Swift 4

 formatter.locale = Locale.current 

Se você quiser mudar de local, você pode fazer assim

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

// Esta é a localidade da localidade da Indonésia. se você quiser usar como por área de telefonia móvel usá-lo como por menção superior Locale.current

 //MARK:- Complete code let formatter = NumberFormatter() formatter.numberStyle = .currency if let formattedTipAmount = formatter.string(from: Int(newString)! as NSNumber) { yourtextfield.text = formattedTipAmount } 

adicionar esta 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 } 

usando:

 let giaTri = value as! Int myGuessTotalCorrect = addSeparateMarkForNumber(int: giaTri) 
 extension Float { var convertAsLocaleCurrency :String { var formatter = NumberFormatter() formatter.numberStyle = .currency formatter.locale = Locale.current return formatter.string(from: self as NSNumber)! } } 

Este trabalho para o rápido 3.1 xcode 8.2.1