I have the following code which works fine except keeping 0 after decimal. The goal is to format the user input as user types on Textfield
MyClass {
static let formatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = NSLocale.current
formatter.maximumFractionDigits = 2
return formatter
}()
}
extension Double {
func formatted() -> String{
return MyClass.amountFormatter.string(from: NSNumber(value: self)) ?? "0"
}
}
This gives me the below output
1256.formatted - 1,256
1256.00.formatted - 1,256 (Need to retain 0 after decimal, desired result - 1,256.00)
1256.05.formatted - 1,256.05
1256.80.formatted - 1,256.8 (Need to retain 0 after decimal, desired result 1,256.80)
1256.5789847.formatted - 1,256.57
How to achieve the desired output
Related
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)
How to convert number formate with separated by ,
Example
Resultant String
"38963.26" value into "38,863.26"
"1013321.22" Value into "10,13,321.22"
//MARK:- Seperator number formate 1000 - 1,000
extension Formatter {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.groupingSeparator = ","
formatter.numberStyle = .decimal
return formatter
}()
}
extension BinaryFloatingPoint {
var formattedWithSeparator: String {
return Formatter.withSeparator.string(for: self) ?? ""
}
}
let resultValue = StringValue.CGFloatValue()?.formattedWithSeparator
print("Resultant", resultValue!)
CGFloatVaule default method for converting String to floatValue.
same like String.floatValue.
For value "38963.26" is gives resultant value "38,963.262" I wonder why its like that extra 2 in decimal.
print("38963.26".CGFloatValue()!.formattedWithSeparator)
Output "38,863.262"
Either set a proper (that uses this style for formatting) locale or set both decimal and grouping separator on your formatter instance since not all Locale might use the same separators.
Then you also need to set max number of fraction digits if you are using float (for some reason this isn't needed for Double)
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = Locale(identifier: "en_US")
formatter.maximumFractionDigits = 2
if let str = formatter.string(for: Float(numberString)) {
print(str)
}
let formatter = NumberFormatter()
formatter.groupingSeparator = ","
formatter.decimalSeparator = "."
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
if let str = formatter.string(for: Float(numberString)) {
print(str)
}
Both yields
38,963.26
Refer this:-
how to add commas to a number in swift?enter link description here
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
let numberString = "38963.26"
if let number = Double(numberString),
let formattedNumber = numberFormatter.string(from: NSNumber(value: number)) {
let formattedString = "\(formattedNumber)"
print(formattedString)
}
There are three issues:
The use of explicit grouping separator.
Forcing the thousands separator to “,” is counterproductive. If the device is in a locale where that’s already the default, you don’t need to specify it. And if the device is in a locale where it’s not default, it will be exceedingly confusing for a user who is not used to seeing “,” thousandths separators. And worse, if you were to override the grouping separator, you should also override the decimal separator, too. If this is for a string to be presented in the user interface, I would suggest not touching the grouping separator (or any of those properties):
static let decimal: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
return formatter
}()
If you really want to force use , for grouping separator and . for decimal separator (even though the user might be in a locale where that might be exceeding confusing were you to present that in the user interface), you should go ahead and change the locale to whatever you want, e.g.
static let decimal: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = Locale(identifier: "en_US") // or "en_IN" or whatever
return formatter
}()
Decimal places.
If you always want two decimal places, then:
static let decimal: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
return formatter
}()
By setting minimum fraction digits, you’re ensured that 42.1 will show up as “42.10”. By setting maximum fraction digits, you’re ensured that 42.33333 will show up as “42.33”.
Issues resulting from conversion of string to binary floating point and back to string.
The fundamental problem with the decimal places is that you’re converting a string to a binary floating point number. If you use Double, you’ll capture more significant digits than you will with Float/CGFloat, but you’re still introducing rounding errors as you convert a string to a binary floating point representation. Float starts introducing conversion errors at the 7th significant decimal digit. Double defers the conversion errors to the 15th significant decimal digit.
You might consider using a numeric format that will capture up to 38 digits without rounding issues, namely Decimal. Thus:
extension NumberFormatter {
static let decimal: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
// specify locale and/or fraction digits as needed
return formatter
}()
}
extension String {
func decimalFormatted() -> String? {
return Decimal(string: self).flatMap { NumberFormatter.decimal.string(for: $0) }
}
}
And then
let string = "38963.26"
let foo = string.decimalFormatted() ?? ""
I need to convert some integers to words and back again, ie: 14 to fourteen and fourteen to 14.
To convert an integer to a word, I am using the .spellout property. Is there a similar method I could apply to a string that would convert it to a numerical value? There does not seem to be an equivalent StringFormatter method.
//opposite of what I am trying to do:
public extension Int {
public var asWord: String {
let numberValue = NSNumber(value: self)
var formatter = NumberFormatter()
formatter.numberStyle = .spellOut
return formatter.string(from: numberValue)!
}
}
You can use this extension method:
public extension String {
func wordToInteger() -> Int? {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .spellOut
return numberFormatter.number(from: self) as? Int
}
}
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)
This is what I do now:
extension Decimal {
var formattedAmount: String {
let formatter = NumberFormatter()
formatter.generatesDecimalNumbers = true
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
return formatter.string(from: self) //mismatch type
}
}
but I cannot create NSNumber from Decimal.
This should work
extension Decimal {
var formattedAmount: String? {
let formatter = NumberFormatter()
formatter.generatesDecimalNumbers = true
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
return formatter.string(from: self as NSDecimalNumber)
}
}
This:
formatter.string(from: ...) // requires a NSNumber
You can either do this:
formatter.string(for: self) // which takes Any as argument
Or:
string(from: self as NSDecimalNumber) // cast self to NSDecimalNumber