Para birimi için Swift'de NSNumberFormatter ile mücadele


87

Kullanıcının bütçesini ve işlemlerini girmesine izin veren bir bütçe uygulaması oluşturuyorum. Kullanıcının ayrı metin alanlarından hem peni hem de poundu girmesine izin vermem ve para birimi simgeleriyle birlikte biçimlendirilmeleri gerekiyor. Şu anda bu iyi çalışıyor ancak şu anda yalnızca GBP ile çalıştığı için yerelleştirilmesini istiyorum. NSNumberFormatter örneklerini Objective C'den Swift'e gizlemek için uğraşıyorum.

İlk sorunum, girdi alanlarının yer tutucularını kullanıcıların konumuna özel olarak ayarlamam gerektiği gerçeğidir. Örneğin. Pound ve Pence, Dolar ve Sentler vb.

İkinci sorun, 10216 ve 32 gibi metin alanlarının her birine girilen değerlerin biçimlendirilmesi ve kullanıcının konumuna özgü para birimi sembolünün eklenmesi gerektiğidir. Yani 10,216,32 £ veya 10,216,32 $ vb. Olur ...

Ayrıca, biçimlendirilmiş sayının sonucunu bir hesaplamada kullanmam gerekiyor. Öyleyse bunu para birimi simgesiyle sorun yaşamadan sorunlarla karşılaşmadan nasıl yapabilirim?

Herhangi bir yardım çok takdir edilecektir.


2
çalışmayan bir kod örneği gönderebilir misiniz?
NiñoScript

Yanıtlar:


207

İşte Swift 3'te nasıl kullanılacağına dair bir örnek. ( Düzenleme : Swift 4'te de çalışıyor)

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

İşte Swift 2'de nasıl kullanılacağına dair eski örnek.

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

Teşekkürler. Sorumu düzenledim ve daha spesifik davrandım.
user3746428

Verdiğiniz örneğe dayanarak, sayı biçimlendirmesini programıma uygulamayı başardım, böylece bit sıralanır. Şimdi, metin alanı yer tutucularını kullanıcıların konumuna göre nasıl ayarlayacağımı bulmam gerekiyor.
user3746428

2
NSNumber'a çevirmenize gerek yok, formatter metodunu kullanabilirsiniz func string (obj: Any?) -> String ?. Yani string(for: price)bunun yerine sadece kullanmanız gerekiyorstring(from: price)
Leo Dabus

1
@LeoDabus haklısınız, bu yöntemi bilmiyordum, cevabımı düzenlemem gerekip gerekmediğinden emin değilim, çünkü NumberFormatter'ın API'sini kullanmayı tercih ederim ve dolaylı olarak izin vermek yerine NSNumber'ı kullanma konusunda açık olurum içine at.
NiñoScript

Formatter.string (from :) sonucunun bir String değil, isteğe bağlı bir String olduğunu (yorumlarda belirtildiği gibi), bu nedenle kullanımdan önce sarmalamanın kaldırılması gerekeceğini unutmayın.
Ali Mübaşir

25

Swift 3:

Size sağlayan bir çözüm arıyorsanız:

  • "5" = "5 ABD doları"
  • "5,0" = "5 ABD doları"
  • "5,00" = "5 ABD doları"
  • "5,5" = "5,50 ABD doları"
  • "5,50" = "5,50 ABD doları"
  • "5,55" = "5,55 ABD doları"
  • "5.234234" = "5.23"

Lütfen aşağıdakileri kullanın:

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

Yeni bir NSNumber nesnesini başlatmanıza gerek yok, func string(for obj: Any?) -> String?bunun yerine formatlayıcı yöntemini kullanabilirsinizstring(from:)
Leo Dabus

19

@ NiñoScript tarafından sağlanan çözümü de bir uzantı olarak uyguladım:

Uzantı

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

Kullanım:

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

Hızlı 3

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

uzantı Swift 3 sürümü ve dizesi için FloatingPoint'i genişletmelidir (from: yöntem NSNumber içindir. FlotingPoint türleri için dize (for :) yöntemini kullanmanız gerekir. Bir Swift 3 uzantısı yayınladım
Leo Dabus

Para birimi için kayan tipler kullanmayın, ondalık kullanın.
adnako

17

Xcode 11 • Swift 5.1

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

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 {
    var currency: String { Formatter.currency.string(for: self) ?? "" }
    var currencyUS: String { Formatter.currencyUS.string(for: self) ?? "" }
    var currencyBR: String { 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"

3
Para birimi için kayan tipler kullanmayın, ondalık kullanın.
adnako


7

Detaylar

  • Xcode 10.2.1 (10E1001), Swift 5

Çözüm

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

Kullanım

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

Sonuçlar

$12,423.42
USD12,423.42
12.423,42 €
12 423,42 EUR
12_423.42 US dollars
12 423,42 Euro

3

@Michael Voccola'nın cevabından Swift 4 için güncellendi:

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

Not: Zorla açma yok, zorla açmalar kötüdür.


2

Swift 4 TextField Uygulandı

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
}

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

Bu hızlı 3.1 xcode 8.2.1 için çalışıyor


Bu kod parçacığı açığız ve bazı yardım sağlamak görülebilir fakat bunun olacağını bunun bir açıklama dahil eğer büyük ölçüde geliştirilmiş bir nasıl ve niçin bu çözer sorunu. Sadece şimdi soran kişi değil, gelecekte okuyucular için soruyu yanıtladığınızı unutmayın! Lütfen açıklama eklemek için yanıtınızı düzenleyin ve hangi sınırlamaların ve varsayımların geçerli olduğuna dair bir gösterge verin.
Toby Speight

Para birimi için kayan tipler kullanmayın, ondalık kullanın.
adnako

0

Swift 4

formatter.locale = Locale.current

yerel ayarı değiştirmek istiyorsanız, bunu şu şekilde yapabilirsiniz

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

// Bu, Endonezya yerel ayarı için yerel ayardır. Cep telefonu alanına göre kullanmak istiyorsanız, yukarıda belirtilen Yerel Ayarlara göre kullanın.

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

0

bu işlevi ekle

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
}

kullanma:

let giaTri = value as! Int
myGuessTotalCorrect = addSeparateMarkForNumber(int: giaTri)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.