number swift nsnumberformatter

Luchando con NSNumberFormatter en Swift por dinero



locale swift (8)

Estoy creando una aplicación de presupuesto que permite al usuario ingresar su presupuesto y las transacciones. Necesito permitir que el usuario ingrese tanto peniques como libras de campos de texto separados y deben formatearse junto con los símbolos de moneda. Esto funciona bien en este momento, pero me gustaría que esté localizado ya que actualmente solo funciona con GBP. He estado luchando para ocultar ejemplos de NSNumberFormatter del objetivo C a Swift.

Mi primer problema es el hecho de que necesito establecer los marcadores de posición para los campos de entrada para que sean específicos de la ubicación de los usuarios. P.ej. Libras y peniques, dólares y centavos, etc.

El segundo problema es que los valores ingresados ​​en cada uno de los campos de texto, como 10216 y 32, deben formatearse y el símbolo de moneda específico de la ubicación de los usuarios debe agregarse. Entonces se convertiría en £ 10,216.32 o $ 10,216.32 etc ...

Además, necesito usar el resultado del número formateado en un cálculo. Entonces, ¿cómo puedo hacer esto sin tener problemas sin tener problemas con el símbolo de moneda?

Cualquier ayuda sería muy apreciada.


Detalles

xCode 9.2, Swift 4

Solución 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

Solución 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")


Aquí hay un ejemplo sobre cómo usarlo en Swift 3. ( Editar : también funciona en 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 €"

Aquí está el viejo ejemplo sobre cómo usarlo en 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 €"


Swift 4

formatter.locale = Locale.current

si quieres cambiar la configuración regional, puedes hacerlo de esta manera

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

// Esta es la configuración regional de Indonesia. si desea usar según el área del teléfono móvil, utilícelo según la mención superior Locale.corrent

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


También implementé la solución proporcionada por @ NiñoScript como una extensión:

Extensión

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


agregar esta función

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 }

utilizando:

let giaTri = value as! Int myGuessTotalCorrect = addSeparateMarkForNumber(int: giaTri)


Swift 3:

Si está buscando una solución que le brinde:

  • "5" = "$ 5"
  • "5.0" = "$ 5"
  • "5,00" = "$ 5"
  • "5.5" = "$ 5.50"
  • "5,50" = "$ 5,50"
  • "5,55" = "$ 5,55"
  • "5.234234" = "5.23"

Por favor use lo siguiente:

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"


extension Float { var convertAsLocaleCurrency :String { var formatter = NumberFormatter() formatter.numberStyle = .currency formatter.locale = Locale.current return formatter.string(from: self as NSNumber)! } }

Esto funciona para swift 3.1 xcode 8.2.1