I am fairly new to Swift and having a great deal of trouble finding a way to add a space as a thousand separator.
What I am hoping to achieve is taking the result of a calculation and displaying it in a textfield so that the format is:
2 358 000
instead of
2358000
for example.
I am not sure if I should be formatting the Int value and then converting it to a String, or adding the space after the Int value is converted to a String. Any help would be greatly appreciated.
You can use NSNumberFormatter to specify a different grouping separator as follow:
update: Xcode 11.5 • Swift 5.2
extension Formatter {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.groupingSeparator = " "
return formatter
}()
}
extension Numeric {
var formattedWithSeparator: String { Formatter.withSeparator.string(for: self) ?? "" }
}
2358000.formattedWithSeparator // "2 358 000"
2358000.99.formattedWithSeparator // "2 358 000.99"
let int = 2358000
let intFormatted = int.formattedWithSeparator // "2 358 000"
let decimal: Decimal = 2358000
let decimalFormatted = decimal.formattedWithSeparator // "2 358 000"
let decimalWithFractionalDigits: Decimal = 2358000.99
let decimalWithFractionalDigitsFormatted = decimalWithFractionalDigits.formattedWithSeparator // "2 358 000.99"
If you need to display your value as currency with current locale or with a fixed locale:
extension Formatter {
static let number = NumberFormatter()
}
extension Locale {
static let englishUS: Locale = .init(identifier: "en_US")
static let frenchFR: Locale = .init(identifier: "fr_FR")
static let portugueseBR: Locale = .init(identifier: "pt_BR")
// ... and so on
}
extension Numeric {
func formatted(with groupingSeparator: String? = nil, style: NumberFormatter.Style, locale: Locale = .current) -> String {
Formatter.number.locale = locale
Formatter.number.numberStyle = style
if let groupingSeparator = groupingSeparator {
Formatter.number.groupingSeparator = groupingSeparator
}
return Formatter.number.string(for: self) ?? ""
}
// Localized
var currency: String { formatted(style: .currency) }
// Fixed locales
var currencyUS: String { formatted(style: .currency, locale: .englishUS) }
var currencyFR: String { formatted(style: .currency, locale: .frenchFR) }
var currencyBR: String { formatted(style: .currency, locale: .portugueseBR) }
// ... and so on
var calculator: String { formatted(groupingSeparator: " ", style: .decimal) }
}
Usage:
1234.99.currency // "$1,234.99"
1234.99.currencyUS // "$1,234.99"
1234.99.currencyFR // "1 234,99 €"
1234.99.currencyBR // "R$ 1.234,99"
1234.99.calculator // "1 234.99"
Note: If you would like to have a space with the same width of a period you can use "\u{2008}"
unicode spaces
formatter.groupingSeparator = "\u{2008}"
You want to use NSNumberFormatter:
let fmt = NSNumberFormatter()
fmt.numberStyle = .DecimalStyle
fmt.stringFromNumber(2358000) // with my locale, "2,358,000"
fmt.locale = NSLocale(localeIdentifier: "fr_FR")
fmt.stringFromNumber(2358000) // "2 358 000"
With Swift 5, when you need to format the display of numbers, NumberFormatter is the right tool.
NumberFormatter has a property called numberStyle. numberStyle can be set to a value of NumberFormatter.Style.decimal in order to set the formatter's style to decimal.
Therefore, in the simplest case when you want to format a number with decimal style, you can use the following Playground code:
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = NumberFormatter.Style.decimal
let amount = 2358000
let formattedString = formatter.string(for: amount)
print(String(describing: formattedString))
According to the user's current locale, this code will print Optional("2,358,000") for en_US or Optional("2 358 000") for fr_FR.
Note that the following code snippet that uses the NumberFormatter's locale property set to Locale.current is equivalent to the previous Playground code:
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = Locale.current
let amount = 2358000
let formattedString = formatter.string(for: amount)
print(String(describing: formattedString))
The Playground code below that uses the NumberFormatter's groupingSeparator property set to Locale.current.groupingSeparator is also equivalent to the former:
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.groupingSeparator = Locale.current.groupingSeparator
let amount = 2358000
let formattedString = formatter.string(for: amount)
print(String(describing: formattedString))
Otherwise, if you want to set the number formatting with a specific locale formatting style, you may use the following Playground code:
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = Locale(identifier: "fr_FR")
let amount = 2358000
let formattedString = formatter.string(for: amount)
print(String(describing: formattedString))
// prints: Optional("2 358 000")
However, if what you really want is to enforce a specific grouping separator, you may use the Playground code below:
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.groupingSeparator = " "
let amount = 2358000
let formattedString = formatter.string(for: amount)
print(String(describing: formattedString))
// prints: Optional("2 358 000")
Leo Dabus's answer translated to Swift 3:
Into any .swift file, out of a class:
struct Number {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.groupingSeparator = " " // or possibly "." / ","
formatter.numberStyle = .decimal
return formatter
}()
}
extension Integer {
var stringWithSepator: String {
return Number.withSeparator.string(from: NSNumber(value: hashValue)) ?? ""
}
}
Usage:
let myInteger = 2358000
let myString = myInteger.stringWithSeparator // "2 358 000"
Code:
//5000000
let formatter = NumberFormatter()
formatter.groupingSeparator = " "
formatter.locale = Locale(identifier: "en_US")
formatter.numberStyle = .decimal.
Output:
5 000 000
I was looking for a currency format like $100,000.00
I accomplished it customizing the implementation Leo Dabus like this
extension Formatter {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencyGroupingSeparator = ","
formatter.locale = Locale(identifier: "en_US") //for USA's currency patter
return formatter
}()
}
extension Numeric {
var formattedWithSeparator: String {
return Formatter.withSeparator.string(for: self) ?? ""
}
}
Try this
func addPoints(inputNumber: NSMutableString){
var count: Int = inputNumber.length
while count >= 4 {
count = count - 3
inputNumber.insert(" ", at: count) // you also can use ","
}
print(inputNumber)
}
The call:
addPoints(inputNumber: "123456")
The result:
123 456 (or 123,456)
I am formatting my currency using locale fr_CA, I use below code to do
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "fr_CA")
formatter.numberStyle = .currency
if let formattedTipAmount = formatter.string(from: 33 as NSNumber) {
print(formattedTipAmount)
}
I am getting output as 33,00 $, but my expected output as 33,00 CAD
Do I need to manually replace last symbol($) with (CAD) or any other proper way of doing it. Kindly help me.
Do I need to manually replace last symbol($) with (CAD)…
Yes, you do.
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "fr_CA")
formatter.numberStyle = .currency
formatter.currencySymbol = "CAD"
if let formattedTipAmount = formatter.string(from: 33) {
print(formattedTipAmount)
}
how to set NumberFormatter to return currency symbol not the iso one but local which is visible in iOS locale settings pane. Like for Polish currency I need to have “zł” symbol not the “PLN”.
I cannot find any way to get it from system as this cannot be hardcoded. IAP localized price also uses “zł” not “PLN”
I tried this way:
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencySymbol = Locale.current.currencySymbol
formatter.maximumFractionDigits = 2
let price = formatter.string(from: (offeringPrice / 12) as NSNumber) ?? ""
but whatever I try to use as currency symbol I always get in return "PLN"
If you set formatter.locale to pl_PL it works:
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.maximumFractionDigits = 2
formatter.currencyCode = "PLN"
let polandLocale = Locale(identifier: "pl_PL")
let usLocale = Locale(identifier: "en_US")
let offeringPrice = 50.0
let price = (offeringPrice / 12) as NSNumber
formatter.locale = usLocale
formatter.string(from: price) // "PLN 4.17"
formatter.locale = polandLocale
formatter.string(from: price) // "4,17 zł"
I've found this solution
func getCurrencySymbol(from currencyCode: String) -> String? {
let locale = NSLocale(localeIdentifier: currencyCode)
if locale.displayName(forKey: .currencySymbol, value: currencyCode) == currencyCode {
let newlocale = NSLocale(localeIdentifier: currencyCode.dropLast() + "_en")
return newlocale.displayName(forKey: .currencySymbol, value: currencyCode)
}
return locale.displayName(forKey: .currencySymbol, value: currencyCode)
}
original answer here: https://stackoverflow.com/a/49146857/1285959
I am using following code to convert string to US currency. However, I could not figure out how to disable round up.
For example, if the string value is "0.000012" code converts it to "$0.00".
The extension I am using it is from this SO answer:
The way I use:
print(Formatter.currency.locale) // "en_US (current)\n"
print(priceUsdInt.currency) // "$1.99\n"
To control rounding (accept 6 digits after point in this case) add formatter.maximumFractionDigits = 6; to your Formatter extension
extension Formatter {
static let currency = NumberFormatter(style: .currency)
static let currencyUS: NumberFormatter = {
let formatter = NumberFormatter(style: .currency)
formatter.locale = Locale(identifier: "en_US")
formatter.maximumFractionDigits = 6;
return formatter
}()
static let currencyBR: NumberFormatter = {
let formatter = NumberFormatter(style: .currency)
formatter.locale = Locale(identifier: "pt_BR")
formatter.maximumFractionDigits = 6;
return formatter
}()
}
0.000012 is should NOT convert to 0.01 , that would be wrong.
If you want to set up a different format you can change the decimal points
String(format: "%0.3f", string)
I am trying to do some calculations of text fields I got it to work using Doubles:
let firstValue = Double(miles.text!)
let secondValue = Double(payPerMile.text!)
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
formatter.locale = Locale.current
formatter.usesGroupingSeparator = true
let result = Double(firstValue! * secondValue!) as NSNumber
grossPay.text = "\(formatter.string(from: result)!)"
While doing more research on the subject I was informed that using Doubles is not the best route to go so I am trying to use NSDecimalNumber instead.
My problem is I can't figure out how to get it to work when switching over.
#IBAction func miles(_ sender: Any) {
let firstValue = NSDecimalNumber(string: miles.text)
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
formatter.usesGroupingSeparator = true
miles.text = "\(formatter.string(from: firstValue as NSNumber)!)"
}
#IBAction func payPerMile(_ sender: Any) {
let firstValue = NSDecimalNumber(string: payPerMile.text)
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
formatter.locale = Locale.current
formatter.usesGroupingSeparator = true
payPerMile.text = "\(formatter.string(from: firstValue as NSNumber)!)"
}
#IBAction func grossPay(_ sender: Any) {
let firstValue = NSDecimalNumber(string: miles.text!)
let secondValue = NSDecimalNumber(string: payPerMile.text!)
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
formatter.locale = Locale.current
formatter.usesGroupingSeparator = true
let result = (firstValue as Decimal) * (secondValue as Decimal) as NSDecimalNumber
grossPay.text = "\(formatter.string(from: result)!)"
just gives me the result of NaN
miles.text is formatted to .decimal
payPerMile.text is formatted to .currency
I am not sure if that could be part of my problem or not.
If payPerMile is formatted as .currency, then it probably contains a currency-character. You cannot simply create an NSDecimalNumber from such a string.
Your second line gives you a NaN for secondValue.
What you can do, is use an NumberFormatter to get the NSNumber from the string.
let formatter = NumberFormatter()
formatter.numberStyle = .currency
let payPerMileNumber = formatter.number(from: "$34.75") // NSNumber with 34.75