在Swift中使用NSNumberFormatter进行货币争夺

时间:2014-07-25 16:47:43

标签: swift nsnumberformatter

我正在创建一个预算应用,允许用户输入预算和交易。我需要允许用户从单独的文本字段输入便士和磅数,并且需要将它们与货币符号一起格式化。我现在工作得很好,但是想把它本地化,因为目前它只适用于GBP。我一直在努力将NSNumberFormatter的例子从Objective C转换为Swift。

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

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

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

非常感谢任何帮助。

10 个答案:

答案 0 :(得分:186)

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

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

答案 1 :(得分:20)

斯威夫特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)"
}

答案 2 :(得分:19)

我已经实现了@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"

Swift 3

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

答案 3 :(得分:13)

Xcode 9•Swift 4

extension Locale {
    static let br = Locale(identifier: "pt_BR")
    static let us = Locale(identifier: "en_US")
    static let uk = Locale(identifier: "en_UK")
}
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 {   // for Swift 3 use FloatingPoint or Int
    var currency: String {
        return Formatter.currency.string(for: self) ?? ""
    }
    var currencyUS: String {
        return Formatter.currencyUS.string(for: self) ?? ""
    }
    var currencyBR: String {
        return 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"

答案 4 :(得分:5)

详细

  • Xcode 10.2.1(10E1001),Swift 5

解决方案

import Foundation

class CurrencyFormatter {      
    static var shared = CurrencyFormatter()
    private(set) lazy var outputFormatter = NumberFormatter()

    class func number(localeString: String? = nil,
                      groupingSeparator: String? = nil,
                      decimalSeparator: String? = nil,
                      style: NumberFormatter.Style = NumberFormatter.Style.currency) -> CurrencyFormatter.Type  {
        var locale = Locale.current
        if let localeString = localeString { locale = Locale(identifier: localeString) }
        shared.outputFormatter.locale = locale
        shared.outputFormatter.decimalSeparator = decimalSeparator ?? locale.decimalSeparator
        shared.outputFormatter.groupingSeparator = groupingSeparator ?? locale.groupingSeparator
        shared.outputFormatter.numberStyle = style
        return self
    }
}

extension Numeric {
    func toCurrency(formatter currencyFormatter: CurrencyFormatter = CurrencyFormatter.shared)  -> String? {
        guard let num = self as? NSNumber else { return nil }
        let outputFormatter = currencyFormatter.outputFormatter
        var formatedSting = outputFormatter.string(from: num)
        guard let locale = outputFormatter.locale else { return formatedSting }
        if let separator = outputFormatter.groupingSeparator, let localeValue = locale.groupingSeparator {
            formatedSting = formatedSting?.replacingOccurrences(of: localeValue, with: separator)
        }
        if let separator = outputFormatter.decimalSeparator, let localeValue = locale.decimalSeparator  {
            formatedSting = formatedSting?.replacingOccurrences(of: localeValue, with: separator)
        }
        return formatedSting
    }
}

用法

let price = 12423.42
print(price.toCurrency() ?? "nil")

CurrencyFormatter.number(style: .currencyISOCode)
print(price.toCurrency() ?? "nil")

CurrencyFormatter.number(localeString: "es_ES")
print(price.toCurrency() ?? "nil")

CurrencyFormatter.number(localeString: "de_DE", groupingSeparator: " ", style: .currencyISOCode)
print(price.toCurrency() ?? "nil")

CurrencyFormatter.number(groupingSeparator: "_", decimalSeparator: ".", style: .currencyPlural)
print(price.toCurrency() ?? "nil")

结果

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

答案 5 :(得分:2)

已从@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 ?? ""
    }
}

注意:没有强制拆开,强制拆开是邪恶的。

答案 6 :(得分:1)

已实现Swift 4 TextField

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
}

答案 7 :(得分:0)

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

答案 8 :(得分:0)

添加此功能

'Declare objects
Dim oSDO As SageDataObject230.SDOEngine
Dim oWS As SageDataObject230.WorkSpace
Dim oSOPRecord As SageDataObject230.SopRecord
Dim oSOPItem_Read As SageDataObject230.SopItem
Dim oSOPItem_Write As SageDataObject230.SopItem
Dim oSOPPost As SageDataObject230.SopPost
Dim oStockRecord As SageDataObject230.StockRecord

'Declare Variables
Dim szDataPath As String

'Create SDO Engine Object
oSDO = New SageDataObject230.SDOEngine

' Select company. The SelectCompany method takes the program install
' folder as a parameter
szDataPath = oSDO.SelectCompany("C:\Documents and Settings\All Users\Application Data\Sage\Accounts\2017\")

'Create Workspace
oWS = oSDO.Workspaces.Add("Example")

'Try to connect
If oWS.Connect(szDataPath, "manager", "", "Example") Then

    'Create objects
    oSOPRecord = oWS.CreateObject("SOPRecord")
    oSOPPost = oWS.CreateObject("SOPPost")
    oSOPItem_Read = oWS.CreateObject("SOPItem")
    oStockRecord = oWS.CreateObject("StockRecord")

    'Read an existing Sales Order
    oSOPRecord.MoveLast()

    'Populate the order header, copying fields from oSOPRecord to oSOPPost
    oSOPPost.Header("INVOICE_NUMBER").Value = oSOPRecord.Fields.Item("INVOICE_NUMBER").Value
    oSOPPost.Header("ACCOUNT_REF").Value = CStr(oSOPRecord.Fields.Item("ACCOUNT_REF").Value)
    oSOPPost.Header("NAME").Value = CStr(oSOPRecord.Fields.Item("NAME").Value)
    oSOPPost.Header("ADDRESS_1").Value = CStr(oSOPRecord.Fields.Item("ADDRESS_1").Value)
    oSOPPost.Header("ADDRESS_2").Value = CStr(oSOPRecord.Fields.Item("ADDRESS_2").Value)
    oSOPPost.Header("ADDRESS_3").Value = CStr(oSOPRecord.Fields.Item("ADDRESS_3").Value)
    oSOPPost.Header("ADDRESS_4").Value = CStr(oSOPRecord.Fields.Item("ADDRESS_4").Value)
    oSOPPost.Header("ADDRESS_5").Value = CStr(oSOPRecord.Fields.Item("ADDRESS_5").Value)
    oSOPPost.Header("DEL_ADDRESS_1").Value = CStr(oSOPRecord.Fields.Item("DEL_ADDRESS_1").Value)
    oSOPPost.Header("DEL_ADDRESS_2").Value = CStr(oSOPRecord.Fields.Item("DEL_ADDRESS_2").Value)
    oSOPPost.Header("DEL_ADDRESS_3").Value = CStr(oSOPRecord.Fields.Item("DEL_ADDRESS_3").Value)
    oSOPPost.Header("DEL_ADDRESS_4").Value = CStr(oSOPRecord.Fields.Item("DEL_ADDRESS_4").Value)
    oSOPPost.Header("DEL_ADDRESS_5").Value = CStr(oSOPRecord.Fields.Item("DEL_ADDRESS_5").Value)
    oSOPPost.Header("CUST_TEL_NUMBER").Value = CStr(oSOPRecord.Fields.Item("CUST_TEL_NUMBER").Value)
    oSOPPost.Header("CONTACT_NAME").Value = CStr(oSOPRecord.Fields.Item("CONTACT_NAME").Value)
    oSOPPost.Header("GLOBAL_TAX_CODE").Value = CShort(oSOPRecord.Fields.Item("GLOBAL_TAX_CODE").Value)
    oSOPPost.Header("ORDER_DATE").Value = CDate(oSOPRecord.Fields.Item("ORDER_DATE").Value)
    oSOPPost.Header("NOTES_1").Value = CStr(oSOPRecord.Fields.Item("NOTES_1").Value)
    oSOPPost.Header("NOTES_2").Value = CStr(oSOPRecord.Fields.Item("NOTES_1").Value)
    oSOPPost.Header("NOTES_3").Value = CStr(oSOPRecord.Fields.Item("NOTES_3").Value)
    oSOPPost.Header("TAKEN_BY").Value = CStr(oSOPRecord.Fields.Item("TAKEN_BY").Value)
    oSOPPost.Header("ORDER_NUMBER").Value = CStr(oSOPRecord.Fields.Item("ORDER_NUMBER").Value)
    oSOPPost.Header("CUST_ORDER_NUMBER").Value = CStr(oSOPRecord.Fields.Item("CUST_ORDER_NUMBER").Value)
    oSOPPost.Header("PAYMENT_REF").Value = CStr(oSOPRecord.Fields.Item("PAYMENT_REF").Value)
    oSOPPost.Header("GLOBAL_NOM_CODE").Value = CStr(oSOPRecord.Fields.Item("GLOBAL_NOM_CODE").Value)
    oSOPPost.Header("GLOBAL_DETAILS").Value = CStr(oSOPRecord.Fields.Item("GLOBAL_DETAILS").Value)
    oSOPPost.Header("ORDER_TYPE").Value = oSOPRecord.Fields.Item("ORDER_TYPE").Value
    oSOPPost.Header("FOREIGN_RATE").Value = CDbl(oSOPRecord.Fields.Item("FOREIGN_RATE").Value)
    oSOPPost.Header("CURRENCY").Value = oSOPRecord.Fields.Item("CURRENCY").Value
    oSOPPost.Header("CURRENCY_USED").Value = oSOPRecord.Fields.Item("CURRENCY_USED").Value

    ' Link header to items
    oSOPItem_Read = oSOPRecord.Link

    'Find the First Record
    oSOPItem_Read.MoveFirst()

    Do

        'Add the existing items to the order
        oSOPItem_Write = oSOPPost.Items.Add

        'Populate the Fields, copying the data from the existing records
        oSOPItem_Write.Fields.Item("STOCK_CODE").Value = CStr(oSOPItem_Read.Fields.Item("STOCK_CODE").Value)
        oSOPItem_Write.Fields.Item("DESCRIPTION").Value = CStr(oSOPItem_Read.Fields.Item("DESCRIPTION").Value)
        oSOPItem_Write.Fields.Item("NOMINAL_CODE").Value = CStr(oSOPItem_Read.Fields.Item("NOMINAL_CODE").Value)
        oSOPItem_Write.Fields.Item("TAX_CODE").Value = CShort(oSOPItem_Read.Fields.Item("TAX_CODE").Value)
        oSOPItem_Write.Fields.Item("QTY_ORDER").Value = CDbl(oSOPItem_Read.Fields.Item("QTY_ORDER").Value)
        oSOPItem_Write.Fields.Item("UNIT_PRICE").Value = CDbl(oSOPItem_Read.Fields.Item("UNIT_PRICE").Value)
        oSOPItem_Write.Fields.Item("NET_AMOUNT").Value = CDbl(oSOPItem_Read.Fields.Item("NET_AMOUNT").Value)
        oSOPItem_Write.Fields.Item("TAX_AMOUNT").Value = CDbl(oSOPItem_Read.Fields.Item("TAX_AMOUNT").Value)
        oSOPItem_Write.Fields.Item("COMMENT_1").Value = CStr(oSOPItem_Read.Fields.Item("COMMENT_1").Value)
        oSOPItem_Write.Fields.Item("COMMENT_2").Value = CStr(oSOPItem_Read.Fields.Item("COMMENT_2").Value)
        oSOPItem_Write.Fields.Item("UNIT_OF_SALE").Value = CStr(oSOPItem_Read.Fields.Item("UNIT_OF_SALE").Value)
        oSOPItem_Write.Fields.Item("FULL_NET_AMOUNT").Value = CDbl(oSOPItem_Read.Fields.Item("FULL_NET_AMOUNT").Value)
        oSOPItem_Write.Fields.Item("TAX_RATE").Value = CDbl(oSOPItem_Read.Fields.Item("TAX_RATE").Value)
        'We now need to ensure that the TAX_FLAG is set the same as the item being read otherwise it will be re calculated
        oSOPItem_Write.Fields.Item("TAX_FLAG").Value = CInt(oSOPItem_Read.Fields.Item("TAX_FLAG").Value)

        'Loop until there are no more existing items
    Loop Until oSOPItem_Read.MoveNext = False

    'destroy the oSOPItem_Write object
    oSOPItem_Write = Nothing

    'write a new item
    oStockRecord.MoveLast()
    oSOPItem_Write = oSOPPost.Items.Add

    ' Populate other fields required for Invoice Item
    ' From 2015 the update method now wraps internal business logic 
    ' that calculates the vat amount if a net amount is given.
    ' If you wish to calculate your own Tax values you will need
    ' to ensure that you set the TAX_FLAG to 1 and set the TAX_AMOUNT value on the item line
    ' ***Note if a NVD is set the item line values will be recalculated 
    ' regardless of the Tax_Flag being set to 1***
    oSOPItem_Write.Fields.Item("STOCK_CODE").Value = oStockRecord.Fields.Item("STOCK_CODE").Value
    oSOPItem_Write.Fields.Item("DESCRIPTION").Value = CStr(oStockRecord.Fields.Item("DESCRIPTION").Value)
    oSOPItem_Write.Fields.Item("NOMINAL_CODE").Value = CStr(oStockRecord.Fields.Item("NOMINAL_CODE").Value)
    oSOPItem_Write.Fields.Item("TAX_CODE").Value = CShort(oStockRecord.Fields.Item("TAX_CODE").Value)
    oSOPItem_Write.Fields.Item("QTY_ORDER").Value = CDbl(2)
    oSOPItem_Write.Fields.Item("UNIT_PRICE").Value = CDbl(50)
    oSOPItem_Write.Fields.Item("NET_AMOUNT").Value = CDbl(100)
    oSOPItem_Write.Fields.Item("FULL_NET_AMOUNT").Value = CDbl(100)
    oSOPItem_Write.Fields.Item("COMMENT_1").Value = CStr("")
    oSOPItem_Write.Fields.Item("COMMENT_2").Value = CStr("")
    oSOPItem_Write.Fields.Item("UNIT_OF_SALE").Value = CStr("")
    oSOPItem_Write.Fields.Item("TAX_RATE").Value = CDbl(20)

    'Destroy the oSOPItem_Write object
    oSOPItem_Write = Nothing

    'Post the order
    If oSOPPost.Update() Then

        MsgBox("Order Updated Successfully")

    Else

        MsgBox("Order Update Failed")

    End If

    'Disconnect and destroy the objects
    oWS.Disconnect()
    oSDO = Nothing
    oWS = Nothing
    oSOPRecord = Nothing
    oSOPItem_Read = Nothing
    oSOPItem_Write = Nothing
    oSOPPost = Nothing
    oStockRecord = Nothing

End If

Exit Sub

使用:

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
}

答案 9 :(得分:-1)

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