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

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

Related

How to convert number to words in swift by using func

Given the integer 'number' in the range of 0 ..<< 1000, print the number as a word.
For example, given: let number : Int = 125
output should be one-hundred and twenty-five
You can use NumberFormatter pretty effectively :) Here's example
let numberFormatter = NumberFormatter()
let number = 12355532
numberFormatter.numberStyle = .spellOut
let numberAsWord = numberFormatter.string(from: NSNumber(value: number))
print(numberAsWord)
You could also extend NSNumber to do this behind the scenes like this
public extension NSNumber {
var spelledOut: String? {
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
return formatter.string(from: self)
}
}
To avoid creating a Number Formatter every time you call this property you can create a static formatter. You can also make the computed property generic to support all numeric types:
extension NumberFormatter {
static let spelled: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
return formatter
}()
}
extension Numeric {
var spelledOut: String? { NumberFormatter.spelled.string(for: self) }
}
let integer = 1234
let integerSpelled = integer.spelledOut // "one thousand two hundred thirty-four"
let double = 123.4
let doubleSpelled = double.spelledOut // "one hundred twenty-three point four"

iOS Swift - Convert double to String precision last value rounded to next value

Example value : 3.00035358. i am trying to convert double value to string
Method 1:
let num = NSNumber(value:self)
let formatter : NumberFormatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.minimumFractionDigits = 4
let str = formatter.string(from: num)!
return str
method2 :
extension Double {
var stringWithoutZeroFraction: String {
return truncatingRemainder(dividingBy: 1) == 0 ? String(d: "%.0f", self) : String(format:"%.4f", self)
}
}
expecting output to be 3.003 but getting like 3.004. i do want my last digit to be rounded to next digit.how to fix tho issue.any help will be appricated.thanks in advance
If you use a NumberFormatter, you need to set the roundingMode to .floor to achieve truncating. Also, if you want to truncate, you probably want to set maximumFractionDigits instead of minimumFractionDigits.
extension Double {
var string: String {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 4
formatter.roundingMode = .floor
return formatter.string(for: self) ?? description
}
}
3.00035358.string // "3.0003"

Change scientific notation to decimal in swift

I want to convert a float value from 1e-05 to 0.00001 in Swift.
I used the following extension:
extension Float {
var avoidNotation: String {
let numberFormatter = NumberFormatter()
numberFormatter.allowsFloats = true
numberFormatter.maximumFractionDigits = 8
numberFormatter.numberStyle = .decimal
return numberFormatter.number(from: "\(self)")!.stringValue
}
}
But when I try to using with float value like 1e-05.avoidNotation result its the same, insted of 0.00001
You should use Formatter's string(for:) method instead of getting the stringValue from the number resulting from your string interpolation:
extension Float {
var avoidNotation: String {
let numberFormatter = NumberFormatter()
numberFormatter.maximumFractionDigits = 8
numberFormatter.numberStyle = .decimal
return numberFormatter.string(for: self) ?? ""
}
}
Float(1e-05).avoidNotation // "0.00001"
I would recommend also instead of creating a NumberFormatter every time you call that property extending Formatter and adding a static formatter. You can also extend FloatingPoint instead of Float so you extend all Floating Point types:
extension Formatter {
static let avoidNotation: NumberFormatter = {
let numberFormatter = NumberFormatter()
numberFormatter.maximumFractionDigits = 8
numberFormatter.numberStyle = .decimal
return numberFormatter
}()
}
extension FloatingPoint {
var avoidNotation: String {
return Formatter.avoidNotation.string(for: self) ?? ""
}
}
Float(1e-05).avoidNotation // "0.00001"
Swift 4.2
Disable scientific notation:
let number = NSNumber(value: floatValue)
print(number.decimalValue)
Extension:
extension Float {
func avoidNotation() -> String {
let number = NSNumber(value: self)
return "\(number.decimalValue)"
}
}

How to separate thousands from a Float value with decimals in Swift

I have the following Float: 1123455432.67899
My desired result is a String: 1,123,455,432.67899
Best case correct , and . based on location (US/Europe)
struct Number {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.groupingSeparator = ","
formatter.numberStyle = .decimal
return formatter
}()
}
let myFloat: Float = 1123455432.67899
let myNumber = NSNumber(value: myFloat)
let formatter = Number.withSeparator
if let result = formatter.string(from: myNumber) {
print(result)
}
This formatter works great as long as my Float has no decimals, als soon as I'm having decimals it starts to "calculate". It calculates up/down based on the 3rd decimal number.
What am I missing? What's the best way to get a String: 1,123,455,432.67899 from a Float with no matter how many decimal numbers? Help is very appreciated.
Edit:
My exact function:
func formatValue(_ value: String ) -> String {
if let double = Double(value) {
let formatter = Number.withSeparator
if let result = formatter.string(from: NSNumber(value: double)) {
return result
} else {
return value
}
} else {
return value
}
}
value is always a number for example 5.5555555555. But in this specific case the result = 5.556.
Use Double instead of Float, the value you are specifying is not well representable in Float:
// [... your current code ...]
let myDouble: Double = 1123455432.67899
let myNumber = NSNumber(value: myDouble)
// [... your current code ...]
1,123,455,432.679
The e+XX notation Float has by default is not just for show, it is there because Float cannot store all digits. See:
let myFloat2: Float = 1123455432.67899
print(myFloat2 == 1123455432) // true
let notRepresentable = Float(exactly:1123455432.67899) // nil
Fundamentally, your issue comes from the floating point imprecision of Float. Using a double precision floating point data type (Double) will alleviate this, to an extent.
Also, you shouldn't hardcode the groupingSeperator, but instead let it be inferred from the current locale (which is the default behaviour).
import Foundation
let numberFormatter: NumberFormatter = {
let nf = NumberFormatter()
nf.numberStyle = .decimal
return nf
}()
let myDouble = 1123455432.67899
let myNumber = NSNumber(value: myDouble)
// It's also directly initializable from a literal
// let myNumber: NSNumber = 1123455432.67899
guard let result = numberFormatter.string(from: myNumber) else { fatalError() }
print(result)
In addition to luk2302's answer, I would suggest to add it as a method to a Double extension, as follows:
extension Double {
func formattedString(_ maximumFractionDigits: Int = 5) -> String? {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.maximumFractionDigits = maximumFractionDigits
return numberFormatter.string(for:self)
}
}
if let formattedString = 1123455432.67899.formattedString() {
print(formattedString) // 1,123,455,432.67899
}
It might improve the ease of getting the desired string.
Thanks for #rmaddy and #LeoDabus for providing useful notes.

How to add custom init for String extension?

How can I add custom init method for String extension?
extension String {
init(_ amount: Double, decimalPlaces: UInt) {
self.init()
let decimalFormat = "%0.\(String(decimalPlaces))f"
let currencyAmount = String(format: decimalFormat, amount)
let currencySign = NSLocalizedString("Defaults.CurrencySign", comment: "currency sign")
let formattedString = "\(currencySign)\(currencyAmount)"
// How to set self to `formattedString` ?
}
}
As result I want to see something like this:
let price = Double(155.15)
let formattedPrice = String(price, decimalPlaces: 2) // formattedPrice = "$155.15"
UPDATED: Final solution
extension String {
init?(currencyAmount: Double) {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = Locale(identifier: NSLocalizedString("Defaults.LocaleCurrencyFormat", comment: "currency sign")) // Defaults.LocaleCurrencyFormat equal "es_US" for US
let formattedAmount = formatter.string(from: NSNumber(value: currencyAmount)) ?? ""
self.init(formattedAmount)
}
}
Edit: Don't format currencies yourself.
However you might think currencies are formatted, you're almost certainly wrong. Just compare:
US/Canada: $3,490,000.89
French Canadian: 3 490 000,89 $
France: 3 490 000,89 €
Germany: 3.490.000,89 €
Instead, use NumberFormatter with numberStyle set to .currency, with a specified locale.
let currencyFormatter = NumberFormatter()
currencyFormatter.usesGroupingSeparator = true
currencyFormatter.numberStyle = .currency
currencyFormatter.locale = Locale.current
let priceString = currencyFormatter.string(from: 9999.99)!
print(priceString) // Displays $9,999.99 in the US locale
Original answer:
The initializers (and mutating methods) of value types can simply assign directly to self:
import Foundation
extension String {
init(_ amount: Double, decimalPlaces: UInt) {
let currencyAmount = String(format: "%\(decimalPlaces).f", amount)
let currencySign = NSLocalizedString("Defaults.CurrencySign", comment: "currency sign")
self = "\(currencySign)\(currencyAmount)"
}
}
let price = Double(155.15)
let formattedPrice = String(price, decimalPlaces: 2) // formattedPrice = "$155.15"