web-dev-qa-db-fra.com

En difficulté avec NSNumberFormatter dans Swift pour de la monnaie

Je crée une application de budget qui permet à l'utilisateur de saisir son budget ainsi que ses transactions. Je dois permettre à l'utilisateur de saisir à la fois des pence et des livres à partir de champs de texte distincts, qui doivent être formatés avec des symboles monétaires. Je travaille très bien pour le moment, mais j'aimerais le localiser, car il ne fonctionne actuellement qu’en GBP. Je me suis efforcé de convertir des exemples NSNumberFormatter d'objectif C à Swift.

Mon premier problème est le fait que je dois définir les espaces réservés pour que les champs de saisie soient spécifiques à l'emplacement des utilisateurs. Par exemple. Livres et pence, dollars et cents etc ...

Le deuxième problème est que les valeurs entrées dans chacun des champs de texte tels que 10216 et 32 ​​doivent être formatées et que le symbole monétaire spécifique à l'emplacement des utilisateurs doit être ajouté. Donc, il deviendrait 10 216,32 £ ou 10 216,32 $, etc. 

De plus, je dois utiliser le résultat du nombre formaté dans un calcul. Alors, comment puis-je faire cela sans rencontrer de problèmes sans rencontrer de problèmes avec le symbole monétaire? 

Toute aide serait très appréciée.

68
user3746428

Voici un exemple d'utilisation de Swift 3 . ( Edit : Fonctionne également dans 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 €"

Voici l'ancien exemple d'utilisation de 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 €"
181
NiñoScript

J'ai également implémenté la solution fournie par @ NiñoScript comme 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)!
    }
}

Utilisation:

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
Michael Voccola

Swift 3:

Si vous cherchez une solution qui vous donne:

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

Veuillez utiliser les éléments suivants:

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

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"
11
Leo Dabus

Détails

xCode 9.2, Swift 4

Solution 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
    }
}

Usage

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

Résultat

 enter image description here

Solution 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
    }
}

Usage

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")
5
Vasily Bodnarchuk

Swift 4 TextField Implémenté

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
Dary

Swift 4 

formatter.locale = Locale.current

si vous voulez changer de lieu, vous pouvez le faire comme ça

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

// Ceci est la locale pour la locale Indonésie. si vous voulez utiliser selon la zone de téléphone mobile, utilisez-le selon la mention supérieure 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
Shakeel Ahmed

Mise à jour pour Swift 4 de @Michael Voccola's answer:

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

Remarque: pas de décompression forcée, la décompression forcée est diabolique.

0
kakubei

ajouter cette fonction

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
}

en utilisant:

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