Berjuang dengan NSNumberFormatter di Swift untuk mata uang


87

Saya membuat aplikasi anggaran yang memungkinkan pengguna memasukkan anggaran serta transaksi mereka. Saya perlu mengizinkan pengguna untuk memasukkan pence dan pound dari bidang teks terpisah dan keduanya harus diformat bersama dengan simbol mata uang. Saya memiliki ini berfungsi dengan baik saat ini tetapi ingin membuatnya dilokalkan karena saat ini hanya berfungsi dengan GBP. Saya telah berjuang untuk menyembunyikan contoh NSNumberFormatter dari Objective C ke Swift.

Masalah pertama saya adalah kenyataan bahwa saya perlu mengatur placeholder untuk bidang input agar spesifik ke lokasi pengguna. Misalnya. Pounds and Pence, Dollars and Cents dll ...

Masalah kedua adalah bahwa nilai yang dimasukkan di setiap bidang teks seperti 10216 dan 32 perlu diformat dan simbol mata uang khusus untuk lokasi pengguna perlu ditambahkan. Jadi itu akan menjadi £ 10.216,32 atau $ 10.216,32 dll ...

Juga, saya perlu menggunakan hasil dari angka yang diformat dalam perhitungan. Jadi bagaimana saya bisa melakukan ini tanpa mengalami masalah tanpa mengalami masalah dengan simbol mata uang?

Bantuan apa pun akan sangat dihargai.


2
dapatkah Anda memposting contoh kode yang tidak berfungsi?
NiñoScript

Jawaban:


207

Berikut adalah contoh tentang cara menggunakannya di Swift 3. ( Edit : Bekerja di Swift 4 juga)

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

Berikut contoh lama tentang cara menggunakannya di 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 €"

Terima kasih. Saya telah mengedit pertanyaan saya dan lebih spesifik.
pengguna3746428

Berdasarkan contoh yang Anda berikan, saya telah berhasil menerapkan pemformatan angka ke dalam program saya, sehingga bit itu diurutkan. Sekarang saya hanya perlu mencari cara untuk mengatur placeholder bidang teks berdasarkan lokasi pengguna.
pengguna3746428

2
Tidak perlu mentransmisikannya ke NSNumber, Anda dapat menggunakan metode formatter func string (untuk obj: Any?) -> String ?. Jadi, Anda hanya perlu menggunakan string(for: price)alih-alihstring(from: price)
Leo Dabus

1
@LeoDabus Anda benar, saya tidak tahu tentang metode itu, saya tidak yakin apakah saya harus mengedit jawaban saya, karena saya pikir saya lebih suka menggunakan API NumberFormatter dan eksplisit tentang menggunakan NSNumber daripada membiarkannya secara implisit melemparkannya ke dalam.
NiñoScript

Perhatikan bahwa hasil dari formatter.string (dari :) adalah String opsional bukan String (seperti yang tersirat dalam komentar) sehingga perlu dibuka bungkusnya sebelum digunakan.
Ali Beadle

25

Cepat 3:

Jika Anda mencari solusi yang memberi Anda:

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

Silakan gunakan yang berikut ini:

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

Tidak perlu menginisialisasi objek NSNumber baru, Anda dapat menggunakan metode formatter func string(for obj: Any?) -> String?sebagai penggantistring(from:)
Leo Dabus

19

Saya telah menerapkan solusi yang disediakan oleh @ NiñoScript sebagai ekstensi juga:

Perpanjangan

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

Pemakaian:

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

Cepat 3

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

ekstensi harus memperluas FloatingPoint untuk versi Swift 3 dan string (dari: metode untuk NSNumber. Untuk jenis FlotingPoint Anda perlu menggunakan metode string (untuk :). Saya telah memposting ekstensi Swift 3
Leo Dabus

Jangan gunakan tipe float untuk mata uang, gunakan desimal.
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
Jangan gunakan tipe float untuk mata uang, gunakan desimal.
adnako


7

Detail

  • Xcode 10.2.1 (10E1001), Swift 5

Larutan

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

Pemakaian

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

Hasil

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

3

Diperbarui untuk Swift 4 dari jawaban @Michael Voccola:

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

Catatan: tidak ada bungkus paksa, bungkus paksa itu jahat.


2

Bidang Teks Swift 4 Diimplementasikan

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

Ini bekerja untuk 3.1 xcode 8.2.1 yang cepat


Meskipun cuplikan kode ini diterima, dan mungkin memberikan sedikit bantuan, akan sangat ditingkatkan jika menyertakan penjelasan tentang bagaimana dan mengapa ini menyelesaikan masalah. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, bukan hanya orang yang bertanya sekarang! Harap edit jawaban Anda untuk menambahkan penjelasan, dan berikan indikasi batasan dan asumsi apa yang berlaku.
Toby Speight

Jangan gunakan tipe float untuk mata uang, gunakan desimal.
adnako

0

Cepat 4

formatter.locale = Locale.current

jika Anda ingin mengubah lokal, Anda dapat melakukannya seperti ini

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

// Ini adalah lokal untuk lokal Indonesia. Jika Anda ingin menggunakan sesuai area ponsel, gunakan sesuai dengan sebutan atas 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

tambahkan fungsi ini

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
}

menggunakan:

let giaTri = value as! Int
myGuessTotalCorrect = addSeparateMarkForNumber(int: giaTri)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.