UITextField 数字小键盘:浮点值用点代替逗号

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

我正在使用由数字键盘填充的文本字段。

问题是,有很多本地区域格式(例如所有欧洲格式),UITextField 的数字键盘用逗号代替点,所以每次我写十进制数时,UITextField 无法识别小数点逗号并且它四舍五入数字;例如 23,07 变成 23.

我该如何解决这个问题? 我想将 textField 设置为固定在美国;可能吗?怎么样?

我用这个读取值:

var importo = (importoPrevistoTF.text as NSString).floatValue

可能与 SO Answer 重复,使用 NSNumberFormatter

示例Swift:

let number = NSNumberFormatter().numberFromString(numberString)
if let number = number {
    let floatValue = Float(number)
}

示例 (Objective-C):

NSNumber *number = [[NSNumberFormatter new] numberFromString: numberString];
float floatValue = number.floatValue;

它可能是 this answer 的副本,但由于原件在 Objective-C 中,这里有一个 Swift 版本:

let label = "23,07"
let formatter = NSNumberFormatter()
let maybeNumber = formatter.numberFromString(label)
if let number = maybeNumber {
    println(number)   // 23.07
}

没有人真正直接解决过这个问题。

也就是说,小数分隔符是区域设置的约定。

iOS 支持根据特定区域设置格式化数字。

如果您纯粹在给定的语言环境中工作,那么一切都应该正常工作。键盘应接受带有正确小数点分隔符的数字。

例如,如果您在欧洲的大多数国家/地区,您将输入逗号作为小数点分隔符。在那些国家输入点是错误的。来自其中一个国家的人不会这样做,因为它是错误的小数点分隔符。欧洲用户将知道使用逗号作为小数点分隔符,而您无需执行任何操作。

如果您在美国,您会使用句点。在美国使用逗号是错误的。

显示十进制数的方式是使用数字格式化程序。当您创建数字格式化程序时,它默认使用当前语言环境。

如果您需要将包含十进制数字的字符串从一种语言环境转换为另一种语言环境,您应该使用 2 个数字格式化程序。在源语言环境中使用格式化程序将字符串转换为浮点数。然后使用具有目标语言环境的格式化程序将数字转换为输出格式的字符串。

只需在默认的当前语言环境中创建一个数字格式化程序,然后创建第二个数字格式化程序并将其语言环境明确设置为您要使用的其他语言环境。

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


使用 NumberFormatter 的本地化方法:

extension NumberFormatter {
    static let shared = NumberFormatter()
}
extension StringProtocol {
    var doubleValue: Double? {
        return NumberFormatter.shared.number(from: String(self))?.doubleValue
    }
}

游乐场测试

// 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
".70".doubleValue  // nil

NumberFormatter.shared.numberStyle  = .currency
"2.7".doubleValue  // nil
"2,7".doubleValue  // nil
".70".doubleValue  // 2.7


NumberFormatter.shared.locale  = Locale(identifier: "pt_BR") // pt_BR (fixed)
"2.7".doubleValue     // nil
"2,7".doubleValue     // nil
"R,70".doubleValue  // 2.7

NumberFormatter.shared.numberStyle = .none
"2.7".doubleValue      // nil
"2,7".doubleValue      // 2.7
"R,70".doubleValue   // nil
        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)

希望对您有所帮助:)

由于NSNumberFormatter在最近的版本Swift中被NumberFormatter所取代,很高兴与您分享一个升级的可能解决方案:

var numberFormatter: NumberFormatter()
importo = Float(numberFormatter.number(from: importoPrevistoTF.text!)!)

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
    }
}

示例:

"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

我找到的解决方案:

let nf = NumberFormatter()
nf.locale = Locale.current
let numberLocalized = nf.number(from: txtAlcool.text!)

就我而言,我在 xcode 上进行测试,一切正常,但在设备上进行测试时,它崩溃了。都是因为在巴西我们使用公制,逗号分隔的十进制“,”。使用此解决方案,它会自动从逗号转换为点。

Swift 4 解决方案,不使用 preferredLanguages 我遇到了 fr_US 和 decimalPad

的问题
extension String {

     func number(style: NumberFormatter.Style = .decimal) -> NSNumber? {
        return [[Locale.current], Locale.preferredLanguages.map { Locale(identifier: [=10=]) }]
            .flatMap { [=10=] }
            .map { locale -> NSNumber? in
                let formatter = NumberFormatter()
                formatter.numberStyle = style
                formatter.locale = locale
                return formatter.number(from: self)
        }.filter { [=10=] != nil }
        .map { [=10=]! }
        .first
    }
}

textfield.text?.number()?.floatValue

您可以使用 NumberFormatter 并过滤不同的小数分隔符来转换它:

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
}

使用当前版本 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)