Swift 3: Replacing a "," with a "." in Double [duplicate] - ios

I'm using a textField which is filled from a numerical pad.
Trouble is that, with lot of local region formats (all european, for example), UITextField's numerical pad has comma instead dot, so everytime I write a decimal number, UITextField can't recognise the decimal comma and it round number; for example 23,07 become 23.
How can I solve this?
I thought to set the textField fixed on USA; is it possible? How?
I read the value using this:
var importo = (importoPrevistoTF.text as NSString).floatValue

Swift 4
extension String {
static let numberFormatter = NumberFormatter()
var doubleValue: Double {
String.numberFormatter.decimalSeparator = "."
if let result = String.numberFormatter.number(from: self) {
return result.doubleValue
} else {
String.numberFormatter.decimalSeparator = ","
if let result = String.numberFormatter.number(from: self) {
return result.doubleValue
}
}
return 0
}
}
"2.25".doubleValue // 2.25
"2,25".doubleValue // 2.25
Localized approach using NumberFormatter:
extension NumberFormatter {
static let shared = NumberFormatter()
}
extension StringProtocol {
var doubleValue: Double? {
return NumberFormatter.shared.number(from: String(self))?.doubleValue
}
}
Playground testing
// User device's default settings for current locale (en_US)
NumberFormatter.shared.locale // en_US (current)
NumberFormatter.shared.numberStyle // none
NumberFormatter.shared.decimalSeparator // "."
"2.7".doubleValue // 2.7
"2,7".doubleValue // nil
"$2.70".doubleValue // nil
NumberFormatter.shared.numberStyle = .currency
"2.7".doubleValue // nil
"2,7".doubleValue // nil
"$2.70".doubleValue // 2.7
NumberFormatter.shared.locale = Locale(identifier: "pt_BR") // pt_BR (fixed)
"2.7".doubleValue // nil
"2,7".doubleValue // nil
"R$2,70".doubleValue // 2.7
NumberFormatter.shared.numberStyle = .none
"2.7".doubleValue // nil
"2,7".doubleValue // 2.7
"R$2,70".doubleValue // nil

Potential duplicate of the SO Answer, use NSNumberFormatter
Example Swift:
let number = NSNumberFormatter().numberFromString(numberString)
if let number = number {
let floatValue = Float(number)
}
Example (Objective-C):
NSNumber *number = [[NSNumberFormatter new] numberFromString: numberString];
float floatValue = number.floatValue;

Nobody has really addressed the issue directly.
That is, the decimal separator is a convention for a locale.
iOS supports formatting numbers based on a particular locale.
If you're working purely in a given locale, then everything should work correctly. The keypad should accept numbers with the correct decimal separator.
If you're in most countries in Europe, for example, you'd enter a comma as the decimal separator. Entering a dot in those countries is wrong. Somebody from one of those countries would not do that, because it is the wrong decimal separator. A European user is going to know to use a comma as the decimal separator and you don't have to do anything.
If you are in the US, you'd use a period. Using a comma in the US would be wrong.
The way you should display a decimal number is with a number formatter. When you create a number formatter, it uses the current locale by default.
If you need to convert a string containing a decimal number from one locale to the other, you should use 2 number formatters. Use a formatter in the source locale to convert the string to a float. Then use a formatter with the destination locale to convert the number to a string in the output format.
Simply create one number formatter in the default current locale, and create a second number formatter and set it's locale explicitly to the other locale that you want to use.

It's probably a duplicate of this answer, but since the original is in Objective-C, here's a Swift version:
let label = "23,07"
let formatter = NSNumberFormatter()
let maybeNumber = formatter.numberFromString(label)
if let number = maybeNumber {
println(number) // 23.07
}

Swift 3: float or double value for string containing floating point with comma
extension String {
var floatValue: Float {
let nf = NumberFormatter()
nf.decimalSeparator = "."
if let result = nf.number(from: self) {
return result.floatValue
} else {
nf.decimalSeparator = ","
if let result = nf.number(from: self) {
return result.floatValue
}
}
return 0
}
var doubleValue:Double {
let nf = NumberFormatter()
nf.decimalSeparator = "."
if let result = nf.number(from: self) {
return result.doubleValue
} else {
nf.decimalSeparator = ","
if let result = nf.number(from: self) {
return result.doubleValue
}
}
return 0
}
}
Example:
"5,456".floatValue //5.456
"5.456".floatValue //5.456
"5,456".doubleValue //5.456
"5.456".doubleValue //5.456
"5,456".doubleValue.rounded() //5
"5,6".doubleValue.rounded() //6

Since NSNumberFormatter was replaced by NumberFormatter in the recent version of Swift, I would have pleasure to share with you an upgraded possible solution:
var numberFormatter: NumberFormatter()
importo = Float(numberFormatter.number(from: importoPrevistoTF.text!)!)

A solution that i've found:
let nf = NumberFormatter()
nf.locale = Locale.current
let numberLocalized = nf.number(from: txtAlcool.text!)
In my case I was testing on xcode and all goes ok, but when testing on device it was crashing. All because in Brazil we use metric system, comma separated decimal ",". With this solution it converts automatically from comma to dot.

Code working with the current version of Swift:
let amount = "8,35"
var counter: Int = 0
var noCommaNumber: String!
for var carattere in (amount) {
if carattere == "," { carattere = "." }
if counter != 0 { noCommaNumber = "\(noCommaNumber ?? "\(carattere)")" + "\(carattere)" } else { noCommaNumber = "\(carattere)" } // otherwise first record will always be nil
counter += 1
}
let importo = Float(noCommaNumber)

Swift 4 solution, without using preferredLanguages I had issues with fr_US and decimalPad
extension String {
func number(style: NumberFormatter.Style = .decimal) -> NSNumber? {
return [[Locale.current], Locale.preferredLanguages.map { Locale(identifier: $0) }]
.flatMap { $0 }
.map { locale -> NSNumber? in
let formatter = NumberFormatter()
formatter.numberStyle = style
formatter.locale = locale
return formatter.number(from: self)
}.filter { $0 != nil }
.map { $0! }
.first
}
}
textfield.text?.number()?.floatValue

You can convert it by using NumberFormatter and filtering the different decimal separators:
func getDoubleFromLocalNumber(input: String) -> Double {
var value = 0.0
let numberFormatter = NumberFormatter()
let decimalFiltered = input.replacingOccurrences(of: "٫|,", with: ".", options: .regularExpression)
numberFormatter.locale = Locale(identifier: "EN")
if let amountValue = numberFormatter.number(from: decimalFiltered) {
value = amountValue.doubleValue
}
return value
}

let number = NSNumberFormatter()
let locale = NSLocale.currentLocale()
let decimalCode = locale.objectForKey(NSLocaleDecimalSeparator) as! NSString
number.decimalSeparator = decimalCode as String
let result = number.numberFromString(textField.text!)
let value = NSNumberFormatter.localizedStringFromNumber(result!.floatValue, numberStyle: .DecimalStyle)
print(value)
Hope, this helps you :)

Related

Swift, converting a number to string, number gets rounded down

I'm having a bit of issue with my code...right now, I am passing a string containing a bunch of numbers, to get converted to a number, comma separators added, then converted back to a string for output. When I add a decimal to my string and pass it in, a number like 996.3658 get truncated to 996.366...
"currentNumber" is my input value, "textOutputToScreen" is my output...
func formatNumber() {
let charset = CharacterSet(charactersIn: ".")
if let _ = currentNumber.rangeOfCharacter(from: charset) {
if let number = Float(currentNumber) {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
guard let formattedNumber = numberFormatter.string(from: NSNumber(value: number)) else { return }
textOutputToScreen = String(formattedNumber)
}
}
else {
if let number = Int(currentNumber) {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
guard let formattedNumber = numberFormatter.string(from: NSNumber(value: number)) else { return }
textOutputToScreen = String(formattedNumber)
}
}
}
Thank you in advance for your help!
The issue there is that you have to set your NumberFormatter minimumFractionDigits to 4. Btw there is no need to initialize a NSNumber object. You can use Formatters string(for: Any) method and pass your Float. Btw I would use a Double (64-bit) instead of a Float (32-bit) and there is no need to initialize a new string g from your formattedNumber object. It is already a String.
Another thing is that you don't need to know the location of the period you can simply use contains instead of rangeOfCharacter method. Your code should look something like this:
extension Formatter {
static let number: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
return formatter
}()
}
func formatNumber(from string: String) -> String? {
if string.contains(".") {
guard let value = Double(string) else { return nil }
Formatter.number.minimumFractionDigits = 4
return Formatter.number.string(for: value)
} else {
guard let value = Int(string) else { return nil }
Formatter.number.minimumFractionDigits = 0
return Formatter.number.string(for: value)
}
}
let label = UILabel()
let currentNumber = "996.3658"
label.text = formatNumber(from: currentNumber) // "996.3658\n"
If you would like to assign the result to your var instead of a label
if let formatted = formatNumber(from: currentNumber) {
textOutputToScreen = formatted
}

UITextField doesn't return a numeric value, because of iOS 11 new "coma" in decimal pad [duplicate]

I'm using a textField which is filled from a numerical pad.
Trouble is that, with lot of local region formats (all european, for example), UITextField's numerical pad has comma instead dot, so everytime I write a decimal number, UITextField can't recognise the decimal comma and it round number; for example 23,07 become 23.
How can I solve this?
I thought to set the textField fixed on USA; is it possible? How?
I read the value using this:
var importo = (importoPrevistoTF.text as NSString).floatValue
Swift 4
extension String {
static let numberFormatter = NumberFormatter()
var doubleValue: Double {
String.numberFormatter.decimalSeparator = "."
if let result = String.numberFormatter.number(from: self) {
return result.doubleValue
} else {
String.numberFormatter.decimalSeparator = ","
if let result = String.numberFormatter.number(from: self) {
return result.doubleValue
}
}
return 0
}
}
"2.25".doubleValue // 2.25
"2,25".doubleValue // 2.25
Localized approach using NumberFormatter:
extension NumberFormatter {
static let shared = NumberFormatter()
}
extension StringProtocol {
var doubleValue: Double? {
return NumberFormatter.shared.number(from: String(self))?.doubleValue
}
}
Playground testing
// User device's default settings for current locale (en_US)
NumberFormatter.shared.locale // en_US (current)
NumberFormatter.shared.numberStyle // none
NumberFormatter.shared.decimalSeparator // "."
"2.7".doubleValue // 2.7
"2,7".doubleValue // nil
"$2.70".doubleValue // nil
NumberFormatter.shared.numberStyle = .currency
"2.7".doubleValue // nil
"2,7".doubleValue // nil
"$2.70".doubleValue // 2.7
NumberFormatter.shared.locale = Locale(identifier: "pt_BR") // pt_BR (fixed)
"2.7".doubleValue // nil
"2,7".doubleValue // nil
"R$2,70".doubleValue // 2.7
NumberFormatter.shared.numberStyle = .none
"2.7".doubleValue // nil
"2,7".doubleValue // 2.7
"R$2,70".doubleValue // nil
Potential duplicate of the SO Answer, use NSNumberFormatter
Example Swift:
let number = NSNumberFormatter().numberFromString(numberString)
if let number = number {
let floatValue = Float(number)
}
Example (Objective-C):
NSNumber *number = [[NSNumberFormatter new] numberFromString: numberString];
float floatValue = number.floatValue;
Nobody has really addressed the issue directly.
That is, the decimal separator is a convention for a locale.
iOS supports formatting numbers based on a particular locale.
If you're working purely in a given locale, then everything should work correctly. The keypad should accept numbers with the correct decimal separator.
If you're in most countries in Europe, for example, you'd enter a comma as the decimal separator. Entering a dot in those countries is wrong. Somebody from one of those countries would not do that, because it is the wrong decimal separator. A European user is going to know to use a comma as the decimal separator and you don't have to do anything.
If you are in the US, you'd use a period. Using a comma in the US would be wrong.
The way you should display a decimal number is with a number formatter. When you create a number formatter, it uses the current locale by default.
If you need to convert a string containing a decimal number from one locale to the other, you should use 2 number formatters. Use a formatter in the source locale to convert the string to a float. Then use a formatter with the destination locale to convert the number to a string in the output format.
Simply create one number formatter in the default current locale, and create a second number formatter and set it's locale explicitly to the other locale that you want to use.
It's probably a duplicate of this answer, but since the original is in Objective-C, here's a Swift version:
let label = "23,07"
let formatter = NSNumberFormatter()
let maybeNumber = formatter.numberFromString(label)
if let number = maybeNumber {
println(number) // 23.07
}
Swift 3: float or double value for string containing floating point with comma
extension String {
var floatValue: Float {
let nf = NumberFormatter()
nf.decimalSeparator = "."
if let result = nf.number(from: self) {
return result.floatValue
} else {
nf.decimalSeparator = ","
if let result = nf.number(from: self) {
return result.floatValue
}
}
return 0
}
var doubleValue:Double {
let nf = NumberFormatter()
nf.decimalSeparator = "."
if let result = nf.number(from: self) {
return result.doubleValue
} else {
nf.decimalSeparator = ","
if let result = nf.number(from: self) {
return result.doubleValue
}
}
return 0
}
}
Example:
"5,456".floatValue //5.456
"5.456".floatValue //5.456
"5,456".doubleValue //5.456
"5.456".doubleValue //5.456
"5,456".doubleValue.rounded() //5
"5,6".doubleValue.rounded() //6
Since NSNumberFormatter was replaced by NumberFormatter in the recent version of Swift, I would have pleasure to share with you an upgraded possible solution:
var numberFormatter: NumberFormatter()
importo = Float(numberFormatter.number(from: importoPrevistoTF.text!)!)
A solution that i've found:
let nf = NumberFormatter()
nf.locale = Locale.current
let numberLocalized = nf.number(from: txtAlcool.text!)
In my case I was testing on xcode and all goes ok, but when testing on device it was crashing. All because in Brazil we use metric system, comma separated decimal ",". With this solution it converts automatically from comma to dot.
Code working with the current version of Swift:
let amount = "8,35"
var counter: Int = 0
var noCommaNumber: String!
for var carattere in (amount) {
if carattere == "," { carattere = "." }
if counter != 0 { noCommaNumber = "\(noCommaNumber ?? "\(carattere)")" + "\(carattere)" } else { noCommaNumber = "\(carattere)" } // otherwise first record will always be nil
counter += 1
}
let importo = Float(noCommaNumber)
Swift 4 solution, without using preferredLanguages I had issues with fr_US and decimalPad
extension String {
func number(style: NumberFormatter.Style = .decimal) -> NSNumber? {
return [[Locale.current], Locale.preferredLanguages.map { Locale(identifier: $0) }]
.flatMap { $0 }
.map { locale -> NSNumber? in
let formatter = NumberFormatter()
formatter.numberStyle = style
formatter.locale = locale
return formatter.number(from: self)
}.filter { $0 != nil }
.map { $0! }
.first
}
}
textfield.text?.number()?.floatValue
You can convert it by using NumberFormatter and filtering the different decimal separators:
func getDoubleFromLocalNumber(input: String) -> Double {
var value = 0.0
let numberFormatter = NumberFormatter()
let decimalFiltered = input.replacingOccurrences(of: "٫|,", with: ".", options: .regularExpression)
numberFormatter.locale = Locale(identifier: "EN")
if let amountValue = numberFormatter.number(from: decimalFiltered) {
value = amountValue.doubleValue
}
return value
}
let number = NSNumberFormatter()
let locale = NSLocale.currentLocale()
let decimalCode = locale.objectForKey(NSLocaleDecimalSeparator) as! NSString
number.decimalSeparator = decimalCode as String
let result = number.numberFromString(textField.text!)
let value = NSNumberFormatter.localizedStringFromNumber(result!.floatValue, numberStyle: .DecimalStyle)
print(value)
Hope, this helps you :)

Ios Swift texfield change a ',' into a '.' [duplicate]

I'm using a textField which is filled from a numerical pad.
Trouble is that, with lot of local region formats (all european, for example), UITextField's numerical pad has comma instead dot, so everytime I write a decimal number, UITextField can't recognise the decimal comma and it round number; for example 23,07 become 23.
How can I solve this?
I thought to set the textField fixed on USA; is it possible? How?
I read the value using this:
var importo = (importoPrevistoTF.text as NSString).floatValue
Swift 4
extension String {
static let numberFormatter = NumberFormatter()
var doubleValue: Double {
String.numberFormatter.decimalSeparator = "."
if let result = String.numberFormatter.number(from: self) {
return result.doubleValue
} else {
String.numberFormatter.decimalSeparator = ","
if let result = String.numberFormatter.number(from: self) {
return result.doubleValue
}
}
return 0
}
}
"2.25".doubleValue // 2.25
"2,25".doubleValue // 2.25
Localized approach using NumberFormatter:
extension NumberFormatter {
static let shared = NumberFormatter()
}
extension StringProtocol {
var doubleValue: Double? {
return NumberFormatter.shared.number(from: String(self))?.doubleValue
}
}
Playground testing
// User device's default settings for current locale (en_US)
NumberFormatter.shared.locale // en_US (current)
NumberFormatter.shared.numberStyle // none
NumberFormatter.shared.decimalSeparator // "."
"2.7".doubleValue // 2.7
"2,7".doubleValue // nil
"$2.70".doubleValue // nil
NumberFormatter.shared.numberStyle = .currency
"2.7".doubleValue // nil
"2,7".doubleValue // nil
"$2.70".doubleValue // 2.7
NumberFormatter.shared.locale = Locale(identifier: "pt_BR") // pt_BR (fixed)
"2.7".doubleValue // nil
"2,7".doubleValue // nil
"R$2,70".doubleValue // 2.7
NumberFormatter.shared.numberStyle = .none
"2.7".doubleValue // nil
"2,7".doubleValue // 2.7
"R$2,70".doubleValue // nil
Potential duplicate of the SO Answer, use NSNumberFormatter
Example Swift:
let number = NSNumberFormatter().numberFromString(numberString)
if let number = number {
let floatValue = Float(number)
}
Example (Objective-C):
NSNumber *number = [[NSNumberFormatter new] numberFromString: numberString];
float floatValue = number.floatValue;
Nobody has really addressed the issue directly.
That is, the decimal separator is a convention for a locale.
iOS supports formatting numbers based on a particular locale.
If you're working purely in a given locale, then everything should work correctly. The keypad should accept numbers with the correct decimal separator.
If you're in most countries in Europe, for example, you'd enter a comma as the decimal separator. Entering a dot in those countries is wrong. Somebody from one of those countries would not do that, because it is the wrong decimal separator. A European user is going to know to use a comma as the decimal separator and you don't have to do anything.
If you are in the US, you'd use a period. Using a comma in the US would be wrong.
The way you should display a decimal number is with a number formatter. When you create a number formatter, it uses the current locale by default.
If you need to convert a string containing a decimal number from one locale to the other, you should use 2 number formatters. Use a formatter in the source locale to convert the string to a float. Then use a formatter with the destination locale to convert the number to a string in the output format.
Simply create one number formatter in the default current locale, and create a second number formatter and set it's locale explicitly to the other locale that you want to use.
It's probably a duplicate of this answer, but since the original is in Objective-C, here's a Swift version:
let label = "23,07"
let formatter = NSNumberFormatter()
let maybeNumber = formatter.numberFromString(label)
if let number = maybeNumber {
println(number) // 23.07
}
Swift 3: float or double value for string containing floating point with comma
extension String {
var floatValue: Float {
let nf = NumberFormatter()
nf.decimalSeparator = "."
if let result = nf.number(from: self) {
return result.floatValue
} else {
nf.decimalSeparator = ","
if let result = nf.number(from: self) {
return result.floatValue
}
}
return 0
}
var doubleValue:Double {
let nf = NumberFormatter()
nf.decimalSeparator = "."
if let result = nf.number(from: self) {
return result.doubleValue
} else {
nf.decimalSeparator = ","
if let result = nf.number(from: self) {
return result.doubleValue
}
}
return 0
}
}
Example:
"5,456".floatValue //5.456
"5.456".floatValue //5.456
"5,456".doubleValue //5.456
"5.456".doubleValue //5.456
"5,456".doubleValue.rounded() //5
"5,6".doubleValue.rounded() //6
Since NSNumberFormatter was replaced by NumberFormatter in the recent version of Swift, I would have pleasure to share with you an upgraded possible solution:
var numberFormatter: NumberFormatter()
importo = Float(numberFormatter.number(from: importoPrevistoTF.text!)!)
A solution that i've found:
let nf = NumberFormatter()
nf.locale = Locale.current
let numberLocalized = nf.number(from: txtAlcool.text!)
In my case I was testing on xcode and all goes ok, but when testing on device it was crashing. All because in Brazil we use metric system, comma separated decimal ",". With this solution it converts automatically from comma to dot.
Code working with the current version of Swift:
let amount = "8,35"
var counter: Int = 0
var noCommaNumber: String!
for var carattere in (amount) {
if carattere == "," { carattere = "." }
if counter != 0 { noCommaNumber = "\(noCommaNumber ?? "\(carattere)")" + "\(carattere)" } else { noCommaNumber = "\(carattere)" } // otherwise first record will always be nil
counter += 1
}
let importo = Float(noCommaNumber)
Swift 4 solution, without using preferredLanguages I had issues with fr_US and decimalPad
extension String {
func number(style: NumberFormatter.Style = .decimal) -> NSNumber? {
return [[Locale.current], Locale.preferredLanguages.map { Locale(identifier: $0) }]
.flatMap { $0 }
.map { locale -> NSNumber? in
let formatter = NumberFormatter()
formatter.numberStyle = style
formatter.locale = locale
return formatter.number(from: self)
}.filter { $0 != nil }
.map { $0! }
.first
}
}
textfield.text?.number()?.floatValue
You can convert it by using NumberFormatter and filtering the different decimal separators:
func getDoubleFromLocalNumber(input: String) -> Double {
var value = 0.0
let numberFormatter = NumberFormatter()
let decimalFiltered = input.replacingOccurrences(of: "٫|,", with: ".", options: .regularExpression)
numberFormatter.locale = Locale(identifier: "EN")
if let amountValue = numberFormatter.number(from: decimalFiltered) {
value = amountValue.doubleValue
}
return value
}
let number = NSNumberFormatter()
let locale = NSLocale.currentLocale()
let decimalCode = locale.objectForKey(NSLocaleDecimalSeparator) as! NSString
number.decimalSeparator = decimalCode as String
let result = number.numberFromString(textField.text!)
let value = NSNumberFormatter.localizedStringFromNumber(result!.floatValue, numberStyle: .DecimalStyle)
print(value)
Hope, this helps you :)

How to format a Double into Currency - Swift 3

I'm new to Swift programming and I've been creating a simple tip calculator app in Xcode 8.2, I have my calculations set up within my IBAction below. But when I actually run my app and input an amount to calculate (such as 23.45), it comes up with more than 2 decimal places. How do I format it to .currency in this case?
#IBAction func calculateButtonTapped(_ sender: Any) {
var tipPercentage: Double {
if tipAmountSegmentedControl.selectedSegmentIndex == 0 {
return 0.05
} else if tipAmountSegmentedControl.selectedSegmentIndex == 1 {
return 0.10
} else {
return 0.2
}
}
let billAmount: Double? = Double(userInputTextField.text!)
if let billAmount = billAmount {
let tipAmount = billAmount * tipPercentage
let totalBillAmount = billAmount + tipAmount
tipAmountLabel.text = "Tip Amount: $\(tipAmount)"
totalBillAmountLabel.text = "Total Bill Amount: $\(totalBillAmount)"
}
}
You can use this string initializer if you want to force the currency to $:
String(format: "Tip Amount: $%.02f", tipAmount)
If you want it to be fully dependent on the locale settings of the device, you should use a NumberFormatter. This will take into account the number of decimal places for the currency as well as positioning the currency symbol correctly. E.g. the double value 2.4 will return "2,40 €" for the es_ES locale and "¥ 2" for the jp_JP locale.
let formatter = NumberFormatter()
formatter.locale = Locale.current // Change this to another locale if you want to force a specific locale, otherwise this is redundant as the current locale is the default already
formatter.numberStyle = .currency
if let formattedTipAmount = formatter.string(from: tipAmount as NSNumber) {
tipAmountLabel.text = "Tip Amount: \(formattedTipAmount)"
}
How to do it in Swift 4:
let myDouble = 9999.99
let currencyFormatter = NumberFormatter()
currencyFormatter.usesGroupingSeparator = true
currencyFormatter.numberStyle = .currency
// localize to your grouping and decimal separator
currencyFormatter.locale = Locale.current
// We'll force unwrap with the !, if you've got defined data you may need more error checking
let priceString = currencyFormatter.string(from: NSNumber(value: myDouble))!
print(priceString) // Displays $9,999.99 in the US locale
You can to convert like that: this func convert keep for you maximumFractionDigits whenever you want to do
static func df2so(_ price: Double) -> String{
let numberFormatter = NumberFormatter()
numberFormatter.groupingSeparator = ","
numberFormatter.groupingSize = 3
numberFormatter.usesGroupingSeparator = true
numberFormatter.decimalSeparator = "."
numberFormatter.numberStyle = .decimal
numberFormatter.maximumFractionDigits = 2
return numberFormatter.string(from: price as NSNumber)!
}
i create it in class Model
then when you call , you can accecpt it another class , like this
print("InitData: result convert string " + Model.df2so(1008977.72))
//InitData: result convert string "1,008,977.72"
you can create an Extension for either string or Int, I would show an example with String
extension String{
func toCurrencyFormat() -> String {
if let intValue = Int(self){
let numberFormatter = NumberFormatter()
numberFormatter.locale = Locale(identifier: "ig_NG")/* Using Nigeria's Naira here or you can use Locale.current to get current locale, please change to your locale, link below to get all locale identifier.*/
numberFormatter.numberStyle = NumberFormatter.Style.currency
return numberFormatter.string(from: NSNumber(value: intValue)) ?? ""
}
return ""
}
}
link to get all locale identifier
The best way to do this is to create an NSNumberFormatter. (NumberFormatter in Swift 3.) You can request currency and it will set up the string to follow the user's localization settings, which is useful.
As an alternative to using a NumberFormatter, If you want to force a US-formatted dollars and cents string you can format it this way:
let amount: Double = 123.45
let amountString = String(format: "$%.02f", amount)
As of Swift 5.5, you can do this with the help of .formatted:
import Foundation
let amount = 12345678.9
print(amount.formatted(.currency(code: "USD")))
// prints: $12,345,678.90
This should support most common currency code, such as "EUR", "GBP", or "CNY".
Similarly, you can append locale to .currency:
print(amount.formatted(
.currency(code:"EUR").locale(Locale(identifier: "fr-FR"))
))
// prints: 12 345 678,90 €
In addition to the NumberFormatter or String(format:) discussed by others, you might want to consider using Decimal or NSDecimalNumber and control the rounding yourself, thereby avoid floating point issues. If you're doing a simple tip calculator, that probably isn't necessary. But if you're doing something like adding up the tips at the end of the day, if you don't round the numbers and/or do your math using decimal numbers, you can introduce errors.
So, go ahead and configure your formatter:
let formatter: NumberFormatter = {
let _formatter = NumberFormatter()
_formatter.numberStyle = .decimal
_formatter.minimumFractionDigits = 2
_formatter.maximumFractionDigits = 2
_formatter.generatesDecimalNumbers = true
return _formatter
}()
and then, use decimal numbers:
let string = "2.03"
let tipRate = Decimal(sign: .plus, exponent: -3, significand: 125) // 12.5%
guard let billAmount = formatter.number(from: string) as? Decimal else { return }
let tip = (billAmount * tipRate).rounded(2)
guard let output = formatter.string(from: tip as NSDecimalNumber) else { return }
print("\(output)")
Where
extension Decimal {
/// Round `Decimal` number to certain number of decimal places.
///
/// - Parameters:
/// - scale: How many decimal places.
/// - roundingMode: How should number be rounded. Defaults to `.plain`.
/// - Returns: The new rounded number.
func rounded(_ scale: Int, roundingMode: RoundingMode = .plain) -> Decimal {
var value = self
var result: Decimal = 0
NSDecimalRound(&result, &value, scale, roundingMode)
return result
}
}
Obviously, you can replace all the above "2 decimal place" references with whatever number is appropriate for the currency you are using (or possibly use a variable for the number of decimal places).
extension String{
func convertDoubleToCurrency() -> String{
let amount1 = Double(self)
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .currency
numberFormatter.locale = Locale(identifier: "en_US")
return numberFormatter.string(from: NSNumber(value: amount1!))!
}
}
In 2022 using Swift 5.5, I created extensions that convert Float or Double into a currency using your device's locale or the locale you pass as an argument. You can check it out here https://github.com/ahenqs/SwiftExtensions/blob/main/Currency.playground/Contents.swift
import UIKit
extension NSNumber {
/// Converts an NSNumber into a formatted currency string, device's current Locale.
var currency: String {
return self.currency(for: Locale.current)
}
/// Converts an NSNumber into a formatted currency string, using Locale as a parameter.
func currency(for locale: Locale) -> String {
let numberFormatter = NumberFormatter()
numberFormatter.usesGroupingSeparator = locale.groupingSeparator != nil
numberFormatter.numberStyle = .currency
numberFormatter.locale = locale
return numberFormatter.string(from: self)!
}
}
extension Double {
/// Converts a Double into a formatted currency string, device's current Locale.
var currency: String {
return NSNumber(value: self).currency(for: Locale.current)
}
/// Converts a Double into a formatted currency string, using Locale as a parameter.
func currency(for locale: Locale) -> String {
return NSNumber(value: self).currency(for: locale)
}
}
extension Float {
/// Converts a Float into a formatted currency string, device's current Locale.
var currency: String {
return NSNumber(value: self).currency(for: Locale.current)
}
/// Converts a Float into a formatted currency string, using Locale as a parameter.
func currency(for locale: Locale) -> String {
return NSNumber(value: self).currency(for: locale)
}
}
let amount = 3927.75 // Can be either Double or Float, since we have both extensions.
let usLocale = Locale(identifier: "en-US") // US
let brLocale = Locale(identifier: "pt-BR") // Brazil
let frLocale = Locale(identifier: "fr-FR") // France
print("\(Locale.current.identifier) -> " + amount.currency) // default current device's Locale.
print("\(usLocale.identifier) -> " + amount.currency(for: usLocale))
print("\(brLocale.identifier) -> " + amount.currency(for: brLocale))
print("\(frLocale.identifier) -> " + amount.currency(for: frLocale))
// will print something like this:
// en_US -> $3,927.75
// en-US -> $3,927.75
// pt-BR -> R$ 3.927,75
// fr-FR -> 3 927,75 €
I hope it helps, happy coding!
extension Float {
var localeCurrency: String {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = .current
return formatter.string(from: self as NSNumber)!
}
}
amount = 200.02
print("Amount Saved Value ",String(format:"%.2f", amountSaving. localeCurrency))
For me Its return 0.00!
Looks to me Extenstion Perfect when accessing it return 0.00! Why?
Here's an easy way I've been going about it.
extension String {
func toCurrency(Amount: NSNumber) -> String {
var currencyFormatter = NumberFormatter()
currencyFormatter.usesGroupingSeparator = true
currencyFormatter.numberStyle = .currency
currencyFormatter.locale = Locale.current
return currencyFormatter.string(from: Amount)!
}
}
Being used as follows
let amountToCurrency = NSNumber(99.99)
String().toCurrency(Amount: amountToCurrency)
Here's how:
let currentLocale = Locale.current
let currencySymbol = currentLocale.currencySymbol
let outputString = "\(currencySymbol)\(String(format: "%.2f", totalBillAmount))"
1st line: You're getting the current locale
2nd line: You're getting the currencySymbol for that locale. ($, £, etc)
3rd line: Using the format initializer to truncate your Double to 2 decimal places.

UITextField's numerical pad: dot instead of comma for float values

I'm using a textField which is filled from a numerical pad.
Trouble is that, with lot of local region formats (all european, for example), UITextField's numerical pad has comma instead dot, so everytime I write a decimal number, UITextField can't recognise the decimal comma and it round number; for example 23,07 become 23.
How can I solve this?
I thought to set the textField fixed on USA; is it possible? How?
I read the value using this:
var importo = (importoPrevistoTF.text as NSString).floatValue
Swift 4
extension String {
static let numberFormatter = NumberFormatter()
var doubleValue: Double {
String.numberFormatter.decimalSeparator = "."
if let result = String.numberFormatter.number(from: self) {
return result.doubleValue
} else {
String.numberFormatter.decimalSeparator = ","
if let result = String.numberFormatter.number(from: self) {
return result.doubleValue
}
}
return 0
}
}
"2.25".doubleValue // 2.25
"2,25".doubleValue // 2.25
Localized approach using NumberFormatter:
extension NumberFormatter {
static let shared = NumberFormatter()
}
extension StringProtocol {
var doubleValue: Double? {
return NumberFormatter.shared.number(from: String(self))?.doubleValue
}
}
Playground testing
// User device's default settings for current locale (en_US)
NumberFormatter.shared.locale // en_US (current)
NumberFormatter.shared.numberStyle // none
NumberFormatter.shared.decimalSeparator // "."
"2.7".doubleValue // 2.7
"2,7".doubleValue // nil
"$2.70".doubleValue // nil
NumberFormatter.shared.numberStyle = .currency
"2.7".doubleValue // nil
"2,7".doubleValue // nil
"$2.70".doubleValue // 2.7
NumberFormatter.shared.locale = Locale(identifier: "pt_BR") // pt_BR (fixed)
"2.7".doubleValue // nil
"2,7".doubleValue // nil
"R$2,70".doubleValue // 2.7
NumberFormatter.shared.numberStyle = .none
"2.7".doubleValue // nil
"2,7".doubleValue // 2.7
"R$2,70".doubleValue // nil
Potential duplicate of the SO Answer, use NSNumberFormatter
Example Swift:
let number = NSNumberFormatter().numberFromString(numberString)
if let number = number {
let floatValue = Float(number)
}
Example (Objective-C):
NSNumber *number = [[NSNumberFormatter new] numberFromString: numberString];
float floatValue = number.floatValue;
Nobody has really addressed the issue directly.
That is, the decimal separator is a convention for a locale.
iOS supports formatting numbers based on a particular locale.
If you're working purely in a given locale, then everything should work correctly. The keypad should accept numbers with the correct decimal separator.
If you're in most countries in Europe, for example, you'd enter a comma as the decimal separator. Entering a dot in those countries is wrong. Somebody from one of those countries would not do that, because it is the wrong decimal separator. A European user is going to know to use a comma as the decimal separator and you don't have to do anything.
If you are in the US, you'd use a period. Using a comma in the US would be wrong.
The way you should display a decimal number is with a number formatter. When you create a number formatter, it uses the current locale by default.
If you need to convert a string containing a decimal number from one locale to the other, you should use 2 number formatters. Use a formatter in the source locale to convert the string to a float. Then use a formatter with the destination locale to convert the number to a string in the output format.
Simply create one number formatter in the default current locale, and create a second number formatter and set it's locale explicitly to the other locale that you want to use.
It's probably a duplicate of this answer, but since the original is in Objective-C, here's a Swift version:
let label = "23,07"
let formatter = NSNumberFormatter()
let maybeNumber = formatter.numberFromString(label)
if let number = maybeNumber {
println(number) // 23.07
}
Swift 3: float or double value for string containing floating point with comma
extension String {
var floatValue: Float {
let nf = NumberFormatter()
nf.decimalSeparator = "."
if let result = nf.number(from: self) {
return result.floatValue
} else {
nf.decimalSeparator = ","
if let result = nf.number(from: self) {
return result.floatValue
}
}
return 0
}
var doubleValue:Double {
let nf = NumberFormatter()
nf.decimalSeparator = "."
if let result = nf.number(from: self) {
return result.doubleValue
} else {
nf.decimalSeparator = ","
if let result = nf.number(from: self) {
return result.doubleValue
}
}
return 0
}
}
Example:
"5,456".floatValue //5.456
"5.456".floatValue //5.456
"5,456".doubleValue //5.456
"5.456".doubleValue //5.456
"5,456".doubleValue.rounded() //5
"5,6".doubleValue.rounded() //6
Since NSNumberFormatter was replaced by NumberFormatter in the recent version of Swift, I would have pleasure to share with you an upgraded possible solution:
var numberFormatter: NumberFormatter()
importo = Float(numberFormatter.number(from: importoPrevistoTF.text!)!)
A solution that i've found:
let nf = NumberFormatter()
nf.locale = Locale.current
let numberLocalized = nf.number(from: txtAlcool.text!)
In my case I was testing on xcode and all goes ok, but when testing on device it was crashing. All because in Brazil we use metric system, comma separated decimal ",". With this solution it converts automatically from comma to dot.
Code working with the current version of Swift:
let amount = "8,35"
var counter: Int = 0
var noCommaNumber: String!
for var carattere in (amount) {
if carattere == "," { carattere = "." }
if counter != 0 { noCommaNumber = "\(noCommaNumber ?? "\(carattere)")" + "\(carattere)" } else { noCommaNumber = "\(carattere)" } // otherwise first record will always be nil
counter += 1
}
let importo = Float(noCommaNumber)
Swift 4 solution, without using preferredLanguages I had issues with fr_US and decimalPad
extension String {
func number(style: NumberFormatter.Style = .decimal) -> NSNumber? {
return [[Locale.current], Locale.preferredLanguages.map { Locale(identifier: $0) }]
.flatMap { $0 }
.map { locale -> NSNumber? in
let formatter = NumberFormatter()
formatter.numberStyle = style
formatter.locale = locale
return formatter.number(from: self)
}.filter { $0 != nil }
.map { $0! }
.first
}
}
textfield.text?.number()?.floatValue
You can convert it by using NumberFormatter and filtering the different decimal separators:
func getDoubleFromLocalNumber(input: String) -> Double {
var value = 0.0
let numberFormatter = NumberFormatter()
let decimalFiltered = input.replacingOccurrences(of: "٫|,", with: ".", options: .regularExpression)
numberFormatter.locale = Locale(identifier: "EN")
if let amountValue = numberFormatter.number(from: decimalFiltered) {
value = amountValue.doubleValue
}
return value
}
let number = NSNumberFormatter()
let locale = NSLocale.currentLocale()
let decimalCode = locale.objectForKey(NSLocaleDecimalSeparator) as! NSString
number.decimalSeparator = decimalCode as String
let result = number.numberFromString(textField.text!)
let value = NSNumberFormatter.localizedStringFromNumber(result!.floatValue, numberStyle: .DecimalStyle)
print(value)
Hope, this helps you :)

Resources