Why NSNumber do not respect locale decimalSeparator - swift

I am using NumberFormatter to convert String to NSNumber with respect of the current locale.
My test locale is Sweden.
So the decimalSeparatorin my case is ","
This is NumberFormatter declaration.
let numberFormatter = NumberFormatter()
numberFormatter.locale = .current
numberFormatter.numberStyle = .decimal
numberFormatter.isLenient = true
Usage.
let number = numberFormatter.number(from:"1,01") // 1.01
But when I try to convert NSNumber back to string.
let stringNumber = number?.stringValue // 1.01
I receive wrong locale decimalSeparator.

Don't use stringValue to convert the number back to a string you wish to display to the user. Use your NumberFormatter to convert the number to a locale friendly string representation.
FYI - there is no need to set the number formatter's locale to .current since that is the default.

Related

don't get currency symbol from NumberFormatter

The output of following Code is: ARS 59.00. Why is there no symbol printed?
let formatter = NumberFormatter()
formatter.currencyCode = "ARS"
formatter.numberStyle = .currency
print(formatter.string(from: NSNumber(value: 59.00)) ?? "na")
Forcing a Custom Locale
To display currency, you will need to show the currency symbol ($, €, ¥, £) for the current locale.
NumberFormatter will show the correct symbol, and the formatting that you might not realize is very different from what you're used to. Different countries use different decimal separators and grouping separators—take a look!
In the USA: $3,490,000.89
In France: 3 490 000,89 €
In Germany: 3.490.000,89 €
See: How to Use NumberFormatter (NSNumberFormatter) in Swift to Make Currency Numbers Easy to Read
So in your case it would be:
let formatter = NumberFormatter()
formatter.currencyCode = "ARS"
formatter.numberStyle = .currency
formatter.locale = Locale(identifier: "es_AR")
print(formatter.string(from: NSNumber(value: 59.00)) ?? "na")
Try this:
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = Locale(identifier: "es_AR")
print(formatter.string(from: NSNumber(value: 59.00)) ?? "na")
check the local identifier here: https://gist.github.com/jacobbubu/1836273

In Swift 5, How to convert a Float to a String localized in order to display it in a textField?

I need to convert a Float to a localized String.
i write this function which is an extension from Float:
func afficherUnFloat() -> String {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.locale = Locale.current
//numberFormatter.maximumFractionDigits = 2
//numberFormatter.maximumIntegerDigits = 6
if let result = numberFormatter.number(from: self) {
return numberFormatter.string(for: result) ?? "0"
}
return "0"
}
but it didn't work:
Here is the exemple
let xxx : Float = 111.222
myTextField.text = String(xxx).afficherUnFloat()
I have installed a pod KSNumericTextField, that limit the numbers in the textfield. He display it only if it is locally formatted.
When i run the app, it doesn't diplay 111,222 in a french region, or 111,222 in an arabic one.
nothing is dislpayed
Note that there is no need to cast your Float to NSNumber. You can use Formatter's method string(for: Any) instead of NumberFormatter's method string(from: NSNumber). Btw it will create a new number formatter every time you call this property. I would make your formatter static:
extension Formatter {
static let decimal: NumberFormatter = {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.locale = .current
numberFormatter.maximumFractionDigits = 2 // your choice
numberFormatter.maximumIntegerDigits = 6 // your choice
return numberFormatter
}()
}
extension FloatingPoint {
var afficherUnFloat: String { Formatter.decimal.string(for: self) ?? "" }
}
let float: Float = 111.222
let string = float.afficherUnFloat // "111.22"
Here is finaly a solution:
extension Float {
func afficherUnFloat() -> String {
let text : NSNumber = self as NSNumber
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.locale = .current
numberFormatter.groupingSeparator = ""
numberFormatter.maximumFractionDigits = 2 // your choice
numberFormatter.maximumIntegerDigits = 6 // your choice
let result = numberFormatter.string(from: text) ?? ""
return result
}
}
With this, you can format every Float to a localized String, compatible with the keyboard choosen by the user, regardless of his locality or langage.
There is no need to force a special keyboard to have a specific decimal separator.
you can use it like this:
let myFloat: Float = 111.222
let myString :String = myFloat.afficherUnFloat()
myString will be displayed as the location requires

How to convert NSNumber to String in Swift4?

How to convert an Array of NSNumber to Array of String in order to display the value in UITableView?
cell.textlabel.text = ?
Code:
var a = [68.208983, 6.373902, 1.34085, 3.974012, 110.484001,
61.380001, 1.325202, 0.8501030000000001, 0.8501030000000001,
0.8501030000000001, 3.647296, 1.28503]
just add
.stringValue
to your NSNumber variable
From what you posted is an array of Double if you don't annotate them explicitly. If the array you posted is as it is, then you need this:
let arrayOfDoubles = [68.208983, 6.373902, 1.34085, 3.974012, 110.484001, 61.380001, 1.325202, 0.8501030000000001, 0.8501030000000001, 0.8501030000000001, 3.647296, 1.28503]
let stringArrayOfDoubles = arrayOfDoubles.map { String($0) }
Or, if you explicitly annotate the type as [NSNumber] then you will need this:
let arrayOfNumbers: [NSNumber] = [68.208983, 6.373902, 1.34085, 3.974012, 110.484001, 61.380001, 1.325202, 0.8501030000000001, 0.8501030000000001, 0.8501030000000001, 3.647296, 1.28503]
let stringArrayOfNumbers = arrayOfNumbers.map { $0.stringValue }
If you're going to display numeric data to the user, it's best to use a number formatter. That way your output will adapt to the formatting that your users are used to and expect based on their locale. It also allows you to configure how the numbers are presented (number of fraction digits, significant digits, rounding, etc.) without having to modify the numbers. For example, if you want to format a number as a decimal with two fraction digits, you would configure the formatter like this:
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
Depending on the user's locale, the output (thousand separator, decimal separator, and even digits(!)) will vary:
formatter.locale = Locale(identifier: "en")
formatter.string(from: 12345.6789) // 12,345.68
formatter.string(from: 0.12345) // 0.12
formatter.locale = Locale(identifier: "sv")
formatter.string(from: 12345.6789) // 12 345,68
formatter.string(from: 0.12345) // 0,12
formatter.locale = Locale(identifier: "hi")
formatter.string(from: 12345.6789) // १२,३४५.६८
formatter.string(from: 0.12345) // ०.१२
formatter.locale = Locale(identifier: "ar")
formatter.string(from: 12345.6789) // ١٢٬٣٤٥٫٦٨
formatter.string(from: 0.12345) // ٠٫١٢
Other number styles can be used to format other types of numeric data like currency, percent, or ordinal numbers:
formatter.locale = Locale(identifier: "en")
formatter.numberStyle = .ordinal
formatter.string(from: 1) // 1st
formatter.string(from: 2) // 2nd
formatter.string(from: 3) // 3rd
formatter.string(from: 4) // 4th
Convert givent value in to String.
If given value is nil then it will return empty string.
class func toString(_ anything: Any?) -> String {
if let any = anything {
if let num = any as? NSNumber {
return num.stringValue
} else if let str = any as? String {
return str
}
}
return ""
}
Just Copy paste this method convert to string without crash issue
Thanks.

Swift convert Currency string to double

I have a string, "$4,102.33" that needs to be converted to double. This will always be US. My only way is a hack to strip out the $ and , and then convert to double. Seems like NSFormatter only lets me convert TO a currency and not from it. Is there a built-in function or better way than just removing the $ and ,? prior to converting it to double?
NumberFormatter can convert to and from string. Also Double cannot represent certain numbers exactly since it's based 2. Using Decimal is slower but safer.
let str = "$4,102.33"
let formatter = NumberFormatter()
formatter.numberStyle = .currency
if let number = formatter.number(from: str) {
let amount = number.decimalValue
print(amount)
}
To convert from String to NSNumber for a given currency is easy:
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = Locale(identifier: "en_US")
let number = formatter.number(from: string)
To get your number as a Double or as a Decimal (preferred) is then direct:
let doubleValue = number?.doubleValue
let decimalValue = number?.decimalValue

Swift how to format a large number with thousands separators?

Is there a simple command to format 1.60543e+06 to 1,605,436???
resultFV.text = String.localizedStringWithFormat("%f", fv)
does not get it.
In Swift 3,
NumberFormatter.localizedString(from: NSNumber(value: whatever), number: NumberFormatter.Style.decimal)
Swift Xcode 6.3, SOLVED (I decided to leave the $ in the code). If you don't want a $ in the output, change .CurrencyStyle to .DecimalStyle
var fv = 3534234.55
var formatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
formatter.maximumFractionDigits = 0;
resultFV.text = formatter.stringFromNumber(fv) // result: $3,534,235 –
You should use a NumberFormatter for that:
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
resultFV.text = numberFormatter.string(from: fv)
Update for Swift 4.1 currency string:
let balance = 1234567
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.maximumFractionDigits = 0
let result = formatter.string(from: NSNumber(value: balance))
// result: $1,234,567
You can change formatter.numberStyle to .decimal to leave it as number without "$" sign.
You can achieve this by using String initializers in Swift 3+:
// 1605436
let value: Int = 1605436
// "1,605,436" where Locale == en_US
let formattedInt = String(format: "%d", locale: Locale.current, value)
// "1,605,436" where Locale == en_US
let formattedDouble = String(format: "%.0f", locale: Locale.current, Double(value))
Update for Swift 5
var unformattedValue : Double = 3534234.55
var formatter = NumberFormatter()
formatter.numberStyle = .currency // or .decimal if desired
formatter.maximumFractionDigits = 2; //change as desired
formatter.locale = Locale.current // or = Locale(identifier: "de_DE"), more locale identifier codes: https://gist.github.com/jacobbubu/1836273
var displayValue : String = formatter.string(from: NSNumber(value: unformattedValue))! // displayValue: "$3,534,235" ```
Why don't you limit the precision, like ".0f"
resultFV.text = String.localizedStringWithFormat("%.0f", fv)
Updated Answer:
var formatter: NSNumberFormatter = NSNumberFormatter()
formatter.numberStyle = NSNumberFormatterStyle.DecimalStyle;
var formattedStr: NSString = formatter.stringFromNumber(NSNumber(double: fv))!
resultFV.text = formattedStr
Updated
Using Data Formatting available in Foundation for macOS 12.0+, iOS 15.0+, tvOS 15.0+, and watchOS 8.0+.
let number: Int = 1000
let formatted = number.formatted(.number.grouping(.never))
print(formatted)
console output: "1000"
number can be any BinaryFloatingPoint or BinaryInteger