Борьба с NSNumberFormatter в Swift за валюту

Я создаю бюджетное приложение, которое позволяет пользователю вводить свой бюджет, а также транзакции. Мне нужно разрешить пользователю вводить как пенсы, так и фунты из отдельных текстовых полей, и их нужно отформатировать вместе с символами валюты. На данный момент я отлично работаю, но хотел бы сделать его локализованным, поскольку в настоящее время он работает только с GBP. Я изо всех сил пытался скрыть примеры NSNumberFormatter от Objective C до Swift.

моя первая проблема заключается в том, что Мне нужно установить заполнители для полей ввода, чтобы они были специфичными для местоположения пользователей. Например. Фунты и пенсы, доллары и центы и т. д...

вторая проблема заключается в том, что значения, введенные в каждом из текстовых полей, таких как 10216 и 32, должны быть отформатированы, а символ валюты, специфичный для местоположения пользователей, должен быть добавлен. Так она станет £10,216.32 или $10,216.32 и т. д...

кроме того, мне нужно использовать результат отформатированного числа в расчете. Так как же я могу? сделать это без проблем без проблем с символа валюты?

любая помощь была бы очень признательна.

8 ответов


вот пример того, как использовать его на Swift 3. ( редактировать: работает в 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) // "3.44"

formatter.locale = Locale(identifier: "es_CL")
formatter.string(from: price) // 3"

formatter.locale = Locale(identifier: "es_ES")
formatter.string(from: price) // "123,44 €"

вот старый пример того, как использовать его на Swift 2.

let price = 123.436

let formatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
// formatter.locale = NSLocale.currentLocale() // This is the default
formatter.stringFromNumber(price) // "3.44"

formatter.locale = NSLocale(localeIdentifier: "es_CL")
formatter.stringFromNumber(price) // 3"

formatter.locale = NSLocale(localeIdentifier: "es_ES")
formatter.stringFromNumber(price) // "123,44 €"

я реализовал решение, предоставленное @NiñoScript в качестве расширения:

расширение

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

использование:

let amount = 100.07
let amountString = amount.asLocaleCurrency
print(amount.asLocaleCurrency())
// prints: "0.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:

Если вы ищете решение, которое дает вам:

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

пожалуйста, используйте следующие:

func cleanDollars(_ value: String?) -> String {
    guard value != nil else { return ".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)             // ".99\n"

Formatter.currency.locale = .br
print(price.currency)  // "R,99\n"

Formatter.currency.locale = .uk
print(price.currency)  // "£1.99\n"

print(price.currencyBR)  // "R,99\n"
print(price.currencyUS)  // ".99\n"

подробности

xCode 9.2, Swift 4

Решение 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
    }
}

использование

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

результат

enter image description here

решение 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
    }
}

использование

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

Если вы хотите изменить язык вы можете сделать это

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

/ / это локаль для Индонезии локаль. если вы хотите использовать в соответствии с областью мобильного телефона, используйте его в соответствии с Локалем верхнего упоминания.ток

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

добавить эту функцию

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
}

использование:

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

это работает для swift 3.1 xcode 8.2.1