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

Posted

技术标签:

【中文标题】在 Swift 中使用 NSNumberFormatter 格式化货币输入【英文标题】:Formatting input for currency with NSNumberFormatter in Swift 【发布时间】:2014-07-25 16:47:42 【问题描述】:

我正在创建一个预算应用程序,允许用户输入他们的预算以及交易。我需要允许用户从单独的文本字段中输入便士和英镑,并且它们需要与货币符号一起格式化。我目前可以正常工作,但希望将其本地化,因为目前它仅适用于 GBP。我一直在努力将 NSNumberFormatter 示例从 Objective-C 转换为 Swift。

我的第一个问题是我需要将输入字段的占位符设置为特定于用户位置。例如。英镑和便士,美元和美分等......

第二个问题是在每个文本字段(例如 10216 和 32)中输入的值需要格式化,并且需要添加特定于用户位置的货币符号。所以它会变成 10,216.32 英镑或 10,216.32 美元等...

另外,我需要在计算中使用格式化数字的结果。那么如何在不遇到货币符号问题的情况下做到这一点呢?

【问题讨论】:

你能发布一个非工作代码的例子吗? 【参考方案1】:

这是一个关于如何在 Swift 3 上使用它的示例。 (编辑:也适用于 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 €"

这是关于如何在 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 €"

【讨论】:

谢谢。我已经编辑了我的问题并且更加具体。 根据您提供的示例,我已设法在我的程序中实现数字格式,以便对该位进行排序。现在我只需要弄清楚如何根据用户位置设置文本字段占位符。 无需将其转换为 NSNumber,您可以使用格式化方法 func string(for obj: Any?) -> String?。所以你只需要使用string(for: price) 而不是string(from: price) @LeoDabus 你是对的,我不知道那个方法,我不确定我是否应该编辑我的答案,因为我想我宁愿使用 NumberFormatter 的 API 并明确关于使用 NSNumber 而不是让它隐式地投射到里面。 请注意,formatter.string(from:) 的结果是一个可选的字符串而不是字符串(如 cmets 所暗示的那样),因此在使用前需要解包。【参考方案2】:

斯威夫特 3:

如果您正在寻找能够为您提供的解决方案:

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

请使用以下内容:

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

【讨论】:

不需要初始化一个新的NSNumber对象你可以使用格式化方法func string(for obj: Any?) -> String?而不是string(from:)【参考方案3】:

我也实现了@NiñoScript 提供的解决方案作为扩展:

扩展

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

用法:

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

斯威夫特 3

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

【讨论】:

extension 应该为 Swift 3 版本和字符串扩展 FloatingPoint(来自:方法是 NSNumber。对于 FlotingPoint 类型,您需要使用 string(for:) 方法。我已经发布了一个 Swift 3 扩展跨度> 货币不要使用浮点类型,使用小数。【参考方案4】:

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"

【讨论】:

货币不要使用浮点类型,使用小数。 ***.com/questions/29782982/…【参考方案5】:

详情

Xcode 10.2.1 (10E1001)、Swift 5

解决方案

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
    

用法

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

结果

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

【讨论】:

【参考方案6】:

根据@Michael Voccola 的回答为 Swift 4 更新:

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

注意:没有强制解包,强制解包是邪恶的。

【讨论】:

【参考方案7】:

已实现 Swift 4 文本字段

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

【讨论】:

【参考方案8】:
extension Float 
    var convertAsLocaleCurrency :String 
        var formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.locale = Locale.current
        return formatter.string(from: self as NSNumber)!
    

这适用于 swift 3.1 xcode 8.2.1

【讨论】:

虽然欢迎使用此代码 sn-p,并且可能会提供一些帮助,但它会是 greatly improved if it included an explanation of howwhy 这解决了问题。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人!请edit您的答案添加解释,并说明适用的限制和假设。 货币不要使用浮点类型,使用小数。【参考方案9】:

斯威夫特 4

formatter.locale = Locale.current

如果你想改变语言环境,你可以这样做

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

// 这是印度尼西亚语言环境的语言环境。如果您想根据手机区域使用,请按照上面提到的 Locale.current 使用它

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

【讨论】:

【参考方案10】:

添加此功能

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

使用:

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

【讨论】:

以上是关于在 Swift 中使用 NSNumberFormatter 格式化货币输入的主要内容,如果未能解决你的问题,请参考以下文章

如何在OC中使用Swift如何在Swift中使用OC

swift 优雅地处理Swift中可本地化的字符串。注意:此代码在Swift 2中,需要在现代Swift中使用更新。

在 Swift 项目中使用 Objective C 类中的 Swift 类

在 Swift 项目中使用 Objective C 类中的 Swift 类

如何在 Swift 中使用 Apple 地图 - 你必须使用 C 还是 Swift 可以?

swift 在swift中使用javascriptcore