好用的 NumberFormatter
做電商在顯示價錢的時候往往要考量到貨幣類型(e.g. TWD, EUR)、貨幣符號(e.g. $, ¥, €)、千分位等等因素,在業界不知為何蠻常看到有人自己在組字串或判斷千分位,其實這些事情可以交給 NumberFormatter 來做。
單純顯示 $$
先寫一個在台灣適用的最簡單例子,因為台幣沒有小數點,所以貨幣的數值後台常常會直接傳 Int 回來,我們就可以對 Int 寫一個 Extension:
extension Int { func currency(showSymbol: Bool = true) -> String? { let number = NSNumber(value: self) let numberFormatter = NumberFormatter() numberFormatter.numberStyle = .currency numberFormatter.currencySymbol = showSymbol ? "$" : "" // note 1 numberFormatter.maximumFractionDigits = 0 // note 2 return numberFormatter.string(from: number) } }
Note
- 其實只要設定 numberStyle = .currency 回傳的字串就會帶錢字號”$”,這邊會特別去做處理是因為有時候我不需要那個錢字號
- maximumFractionDigits 指的是要顯示小數點後幾位,台幣顯示就會指定為 0。
在使用時只要在整數後面呼叫 .currency() 就可以拿到帶有錢字號即千分位的貨幣字串。
print("currency: \(String(describing: 1920.currency()))") // output => currency: Optional("$1,920")
指定貨幣代碼
我們也可以將貨幣代碼(currency code)傳給 number formatter。
這邊提一下若是有小數點的貨幣,應該改用 Decimal data type 以確保其後續運算不會因為浮點數的特性而導致計算失準,對浮點數有興趣可以參考 iPlayground 的這則分享。
extension Decimal { func currency(currencyCode: String) -> String? { let number = NSDecimalNumber(decimal: self) // note 1 let numberFormatter = NumberFormatter() numberFormatter.numberStyle = .currency // note 2 numberFormatter.currencyCode = currencyCode numberFormatter.maximumFractionDigits = 2 return numberFormatter.string(from: number) } } print("currency: \(String(describing: Decimal(1920).currency(currencyCode: "EUR")))") // output => currency: Optional("€1,920.00")
Note
- Decimal 型別需轉成 NSDecimalNumber 而非 NSNumber
- numberStyle 除了 .currency 以外還有包含 .currencyISOCode 及 .currencyPlural, .currencyAccounting 等等可以選擇
- .currency: €1,920.00
- .currencyISOCode: EUR 1920.00
- .currencyAccounting: 若是台幣(TWD)會顯示 NT$1920,歐元則保持 €1,920.00
- .currencyPlural: 目前測試都會回傳 1920.00 US dollars
支援貨幣在地化
最後,我們也可以指定 local 給 NumberFormatter 達到在地化的需求:
let numberFormatter = NumberFormatter() numberFormatter.locale = Locale.current ...