Đấu tranh với NSNumberFormatter trong Swift cho tiền tệ


86

Tôi đang tạo một ứng dụng ngân sách cho phép người dùng nhập ngân sách của họ cũng như các giao dịch. Tôi cần cho phép người dùng nhập cả pence và pound từ các trường văn bản riêng biệt và chúng cần được định dạng cùng với các ký hiệu tiền tệ. Tôi thấy cái này đang hoạt động tốt vào lúc này nhưng tôi muốn bản địa hóa nó vì hiện tại nó chỉ hoạt động với GBP. Tôi đã cố gắng che đậy các ví dụ về NSNumberFormatter từ Objective C đến Swift.

Vấn đề đầu tiên của tôi là thực tế là tôi cần đặt trình giữ chỗ cho các trường đầu vào cụ thể cho vị trí của người dùng. Ví dụ. Bảng và Pence, Đô la và Xu, v.v.

Vấn đề thứ hai là các giá trị được nhập vào từng trường văn bản như 10216 và 32 cần được định dạng và ký hiệu tiền tệ cụ thể cho vị trí của người dùng cần được thêm vào. Vì vậy, nó sẽ trở thành £ 10.216,32 hoặc $ 10,216,32, v.v.

Ngoài ra, tôi cần sử dụng kết quả của số được định dạng trong một phép tính. Vì vậy, làm thế nào tôi có thể làm điều này mà không gặp sự cố mà không gặp sự cố với ký hiệu tiền tệ?

Bất kì sự trợ giúp nào đều được đánh giá cao.


2
bạn có thể đăng một ví dụ về mã không hoạt động không?
NiñoScript

Câu trả lời:


205

Đây là một ví dụ về cách sử dụng nó trên Swift 3. ( Chỉnh sửa : Cũng hoạt động trong 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 €"

Đây là ví dụ cũ về cách sử dụng nó trên 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 €"

Cảm ơn. Tôi đã chỉnh sửa câu hỏi của mình và cụ thể hơn.
user3746428,

Dựa trên ví dụ bạn cung cấp, tôi đã quản lý để triển khai định dạng số vào chương trình của mình, vì vậy bit đó được sắp xếp. Bây giờ tôi chỉ cần tìm cách đặt chỗ dành sẵn cho trường văn bản dựa trên vị trí của người dùng.
user3746428

2
Không cần truyền nó tới NSNumber, bạn có thể sử dụng phương thức định dạng func string (đối với obj: Any?) -> String ?. Vì vậy, bạn chỉ cần sử dụng string(for: price)thay vìstring(from: price)
Leo Dabus

1
@LeoDabus bạn nói đúng, tôi không biết về phương pháp đó, tôi không chắc liệu mình có nên chỉnh sửa câu trả lời của mình hay không, vì tôi nghĩ rằng tôi muốn sử dụng API của NumberFormatter và rõ ràng về việc sử dụng NSNumber hơn là để nó ngầm đúc nó bên trong.
NiñoScript

Lưu ý rằng kết quả của formatter.string (from :) là một Chuỗi tùy chọn không phải là Chuỗi (như ngụ ý của các nhận xét) vì vậy sẽ cần phải mở gói trước khi sử dụng.
Ali Beadle

25

Swift 3:

Nếu bạn đang tìm kiếm một giải pháp mang lại cho bạn:

  • "5" = "5 đô la"
  • "5.0" = "$ 5"
  • "5,00" = "5 đô la"
  • "5.5" = "$ 5,50"
  • "5,50" = "5,50 đô la"
  • "5,55" = "5,55 đô la"
  • "5.234234" = "5.23"

Vui lòng sử dụng những thứ sau:

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

Không cần phải khởi tạo một đối tượng mới NSNumber bạn có thể sử dụng định dạng phương pháp func string(for obj: Any?) -> String?thay vìstring(from:)
Leo Dabus

19

Tôi cũng đã triển khai giải pháp do @ NiñoScript cung cấp dưới dạng tiện ích mở rộng:

Sự mở rộng

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

Sử dụng:

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

mở rộng nên mở rộng FloatingPoint cho Swift 3 phiên bản và chuỗi (từ: phương pháp là cho NSNumber Đối với các loại FlotingPoint bạn cần sử dụng chuỗi (ví :) phương pháp tôi đã đăng tải một phần mở rộng Swift 3..
Leo Dabus

Không sử dụng kiểu float cho tiền tệ, hãy sử dụng số thập phâ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
Không sử dụng kiểu float cho tiền tệ, hãy sử dụng số thập phân.
adnako


7

Chi tiết

  • Xcode 10.2.1 (10E1001), Swift 5

Giải pháp

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

Sử dụng

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

Các kết quả

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

3

Cập nhật cho Swift 4 từ câu trả lời của @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 ?? ""
    }
}

Lưu ý: không có force-unraps, force-unraps là ác.


2

Trường văn bản Swift 4 được triển khai

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

Điều này hoạt động cho nhanh chóng 3.1 xcode 8.2.1


Mặc dù đoạn mã này được hoan nghênh và có thể cung cấp một số trợ giúp, nó sẽ được cải thiện đáng kể nếu nó bao gồm giải thích về cách thứclý do tại sao đoạn mã này giải quyết được vấn đề. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai, không chỉ người hỏi bây giờ! Vui lòng chỉnh sửa câu trả lời của bạn để thêm giải thích và đưa ra dấu hiệu về những giới hạn và giả định nào được áp dụng.
Toby Speight

Không sử dụng kiểu float cho tiền tệ, hãy sử dụng số thập phân.
adnako

0

Swift 4

formatter.locale = Locale.current

nếu bạn muốn thay đổi ngôn ngữ, bạn có thể làm như thế này

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

// Đây là ngôn ngữ cho ngôn ngữ Indonesia. nếu bạn muốn sử dụng theo khu vực điện thoại di động, hãy sử dụng nó theo đề cập ở trên 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

thêm chức năng này

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
}

sử dụng:

let giaTri = value as! Int
myGuessTotalCorrect = addSeparateMarkForNumber(int: giaTri)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.