在 Swift 中使用 NSNumberFormatter 格式化货币输入

我正在创建一个预算应用程序,允许用户输入他们的预算以及交易。我需要允许用户从不同的文本字段输入便士和英镑,它们需要与货币符号一起格式化。我有这个工作良好的时刻,但希望使其本地化,因为目前它只与 GBP 的工作。我一直在努力将 NSNumberFormatter 示例从 Objective-C 转换为 Swift。

My first issue is the fact that I need to set the placeholders for the input fields to be specific to the users location. Eg. Pounds and Pence, Dollars and Cents etc...

The second issue is that the values inputted in each of the text fields such as 10216 and 32 need to be formatted and the currency symbol specific to the users location needs to be added. So it would become £10,216.32 or $10,216.32 etc...

另外,我需要在计算中使用格式化数字的结果。那么,我怎样才能做到这一点,而不会遇到问题,而不会遇到问题的货币符号?

102016 次浏览

Here's an example on how to use it on Swift 3. ( Edit: Works in Swift 5 too )

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

Here's the old example on how to use it on 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 €"

I have implemented the solution provided by @NiñoScript as an extension as well:

Extension

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

Usage:

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

Swift 3:

If you are looking for a solution that gives you:

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

Please use the following:

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)"
}
extension Float {
var convertAsLocaleCurrency :String {
var formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = Locale.current
return formatter.string(from: self as NSNumber)!
}
}

This working for swift 3.1 xcode 8.2.1

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"

Details

  • Xcode 10.2.1 (10E1001), Swift 5

Solution

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

Usage

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

Results

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

Swift 4

formatter.locale = Locale.current

if you want to change locale you can do it like this

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

// This is locale for Indonesia locale. if you want use as per mobile phone area use it as per upper mention Locale.current

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

add this function

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
}

using:

let giaTri = value as! Int
myGuessTotalCorrect = addSeparateMarkForNumber(int: giaTri)

Updated for Swift 4 from @Michael Voccola's answer:

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

Note: no force-unwraps, force-unwraps are evil.

Swift 4 TextField Implemented

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
}