Memformat input untuk mata uang dengan NSNumberFormatter di Swift

Saya membuat aplikasi anggaran yang memungkinkan pengguna memasukkan anggaran serta transaksinya. Saya perlu mengizinkan pengguna memasukkan pence dan pound dari kolom teks terpisah dan keduanya perlu 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 mengonversi contoh NSNumberFormatter dari Objective-C ke Swift.

Masalah pertama saya adalah kenyataan bahwa saya perlu mengatur placeholder untuk kolom input agar spesifik dengan lokasi pengguna. Misalnya. Pound dan Pence, Dolar dan Sen, dll...

Masalah kedua adalah nilai yang dimasukkan di setiap kolom 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...

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


person user3746428    schedule 25.07.2014    source sumber
comment
dapatkah Anda memposting contoh kode yang tidak berfungsi?   -  person NiñoScript    schedule 25.07.2014


Jawaban (10)


Berikut ini contoh cara menggunakannya di Swift 3. ( Edit: Berfungsi juga di Swift 5 )

let price = 123.436 as NSNumber

let formatter = NumberFormatter()
formatter.numberStyle = .currency
// formatter.locale = NSLocale.currentLocale() // This is the default
// In Swift 4, this ^ was 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 €"
person NiñoScript    schedule 25.07.2014
comment
Terima kasih. Saya telah mengedit pertanyaan saya dan menjadi lebih spesifik. - person user3746428; 25.07.2014
comment
Berdasarkan contoh yang Anda berikan, saya telah berhasil menerapkan pemformatan angka ke dalam program saya, sehingga bit tersebut terurut. Sekarang saya hanya perlu mencari cara untuk mengatur placeholder bidang teks berdasarkan lokasi pengguna. - person user3746428; 25.07.2014
comment
Tidak perlu mentransmisikannya ke NSNumber, Anda dapat menggunakan metode formatter func string (untuk obj: Ada?) -› String?. Jadi Anda hanya perlu menggunakan string(for: price) daripada string(from: price) - person Leo Dabus; 22.03.2017
comment
@LeoDabus Anda benar, saya tidak tahu tentang metode itu, saya tidak yakin apakah saya harus mengedit jawaban saya, karena menurut saya saya lebih suka menggunakan API NumberFormatter dan secara eksplisit menggunakan NSNumber daripada membiarkannya secara implisit melemparkannya ke dalam. - person NiñoScript; 22.03.2017
comment
Perhatikan bahwa hasil formatter.string(from:) adalah String opsional, bukan String (seperti yang tersirat dalam komentar) sehingga perlu dibuka bungkusnya sebelum digunakan. - person Ali Beadle; 10.09.2017
comment
Pengembalian string opsional adalah artefak konversi ke NSNumber, di sini, di swift-land kita tahu bahwa itu adalah angka sebenarnya dan tidak akan pernah gagal, jadi kita bisa membuka paksa saja. - person NiñoScript; 25.09.2018

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)"
}
person Gregg    schedule 08.12.2016
comment
Tidak perlu menginisialisasi objek NSNumber baru, Anda dapat menggunakan metode formatter func string(for obj: Any?) -> String? alih-alih string(from:) - person Leo Dabus; 22.03.2017

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

Ekstensi

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

Penggunaan:

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)!
    }
}
person Michael Voccola    schedule 24.04.2015
comment
ekstensi harus memperluas FloatingPoint untuk versi Swift 3 dan metode string(dari: adalah untuk NSNumber. Untuk tipe FlotingPoint Anda perlu menggunakan metode string(untuk:). Saya telah memposting ekstensi Swift 3 - person Leo Dabus; 22.03.2017
comment
Jangan gunakan tipe float untuk mata uang, gunakan desimal. - person adnako; 14.03.2018

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"
person Leo Dabus    schedule 22.03.2017
comment
Jangan gunakan tipe float untuk mata uang, gunakan desimal. - person adnako; 14.03.2018
comment
stackoverflow.com/questions/29782982/ - person Leo Dabus; 28.11.2019

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

Penggunaan

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
person Vasily Bodnarchuk    schedule 08.12.2017

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 pembukaan paksa, pembukaan paksa adalah kejahatan.

person kakubei    schedule 05.02.2019

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
}
person Pengguna    schedule 12.02.2019

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

Ini berfungsi untuk Swift 3.1 xcode 8.2.1

person du Phung    schedule 01.03.2017
comment
Meskipun cuplikan kode ini diterima, dan mungkin memberikan bantuan, akan sangat ditingkatkan jika menyertakan penjelasan tentang caranya dan mengapa ini menyelesaikan masalah. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa mendatang, bukan hanya untuk orang yang bertanya sekarang! Harap edit jawaban Anda untuk menambahkan penjelasan, dan berikan indikasi batasan dan asumsi apa yang berlaku. - person Toby Speight; 01.03.2017
comment
Jangan gunakan tipe float untuk mata uang, gunakan desimal. - person adnako; 14.03.2018

Cepat 4

formatter.locale = Locale.current

jika Anda ingin mengubah lokal Anda bisa 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 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
}
person Shakeel Ahmed    schedule 16.04.2018

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)
person coders    schedule 13.05.2018