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

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
}

Related

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 :)

The NSFormatter for Converting English Number to persian or arabic Number in Swift 3

I read the similar questions here and Write this method in my app
let formatter = NumberFormatter()
func convertEngNumToPersianNum(num: String)->String{
let number = NSNumber(value: Int(num)!)
let format = NumberFormatter()
format.locale = Locale(identifier: "fa_IR")
let faNumber = format.string(from: number)
return faNumber!
}
I didn't get Error But I didn't get the result too!
my Number code is this :
let checkNumber = Home2ViewController().customtitle.count
personalCustom.text = ("\(checkNumber)")
I used another Number in another View Controller that works But I want to show this Number in persian or arabic number format not in English format
Try this :
func convertEngNumToPersianNum(num: String)->String{
//let number = NSNumber(value: Int(num)!)
let format = NumberFormatter()
format.locale = Locale(identifier: "fa_IR")
let number = format.number(from: num)
let faNumber = format.string(from: number!)
return faNumber!
}
OR repalce with your line
let number = format.number(from: num)
let faNumber = format.string(from: number!)
You can do something like,
let formatter = NumberFormatter()
formatter.locale = NSLocale.current // you can specify locale that you want
formatter.numberStyle = .decimal
formatter.usesGroupingSeparator = true
let number = formatter.number(from: "١٠.٠٠")
print(number ?? "")
To convert to Arabic while keeping the leading zeros
func convertToArDigits(_ digits: String) -> String {
// We need a CFMutableString and a CFRange:
let cfstr = NSMutableString(string: digits) as CFMutableString
var range = CFRange(location: 0, length: CFStringGetLength(cfstr))
// Do the transliteration (this mutates `cfstr`):
CFStringTransform(cfstr, &range, kCFStringTransformLatinArabic, false)
// Convert result back to a Swift string:
return (cfstr as String)
}
extension String {
public var faToEnDigits : String {
let farsiNumbers = ["٠": "0","١": "1","٢": "2","٣": "3","٤": "4","٥": "5","٦": "6","٧": "7","٨": "8","٩": "9"]
var txt = self
farsiNumbers.map { txt = txt.replacingOccurrences(of: $0, with: $1)}
return txt
}
public var enToFaDigits : String {
let englishNumbers = ["0": "۰","1": "۱","2": "۲","3": "۳","4": "۴","5": "۵","6": "۶","7": "۷","8": "۸","9": "۹"]
var txt = self
englishNumbers.map { txt = txt.replacingOccurrences(of: $0, with: $1)}
return txt
}
}

Swift 3: Replacing a "," with a "." in Double [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 :)

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