如何将 UILabel 文本格式化为特定于语言环境 NSNumberFormatterStyle.DecimalStyle
How to format UILabel text to locale specific NSNumberFormatterStyle.DecimalStyle
我有一个 UILabel
来显示输入文本(有十进制数字)。我想要做的是,UILabel
文本可以根据语言环境显示。例如-
"1234.56" should be shown as "1,234.56" for US locale, "1.234,56" for DE (Germany) locale and so on.
以下是我为实现这一目标所做的工作 -
NSNumberFormatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
NSNumberFormatter.locale = NSLocale(localeIdentifier: language)
NSNumberFormatter.maximumFractionDigits = 16
let displayVal: Double = NSNumberFormatter.numberFromString(displayText.text!).doubleValue
displayText.text = NSNumberFormatter.stringFromNumber(displayVal)
其中 displayText
是显示输入的 UILabel
。
它工作正常,直到 4 位数字,即“1234”显示为“1,234”(对于美国语言环境)。但是一旦添加了第 5 位数字,nil
就返回了 displayVal
常量变量。
我可以从函数定义中猜到格式化 displayText
文本字符串失败,当 numberFromString
尝试按照美国语言环境格式化它时可能是“1,2345”但失败了这不符合美国语言环境格式。
谁能提出解决此问题的方法或更好的实施方法?
您需要确保数字格式化程序与您传递给它的字符串匹配。如果有任何不匹配,它将变为 return nil,并且 doubleValue 调用将变为 return 0.
如果您有针对美国格式化的字符串,使用逗号的分组分隔符,那么您应该将数字格式化程序的 groupingSeparator
属性 设置为逗号。然后格式化程序应该处理像“1,234”这样的输入字符串。正如您所说,“1,2345”不是用于显示数字的普通美国格式。
您可能还需要更改 groupingSize 设置(如果我没记错的话,字符串“1,2345”的 groupingSize 为 4。
您解析的字符串来自哪里?你知道他们使用什么语言环境吗?用户是否在使用 en-US
语言环境设置的设备上输入“1,2345”?如果是,为什么?这不是美国英语的正常格式。
您可以执行类似以下操作,即去掉任何千位分隔符,从中获取一个数字,然后使用千位分隔符重新格式化:
@IBAction func didEditingChanged(_ sender: UITextField) {
guard let text = sender.text else { return }
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
// get thousands separator
let thousandsSeparator = formatter.groupingSeparator ?? ","
// strip thousands separators out
let stripped = String(text.filter { return String([=10=]) != thousandsSeparator })
// now, re-insert them, if any
if let number = formatter.numberFromString(stripped) {
sender.text = formatter.stringFromNumber(number)
}
}
假设您将它连接到 "Editing Changed" 以便它不断更新,这会引入一些问题。例如,要输入尾随小数位,您可能必须手动检查并允许保留:
@IBAction func didEditingChanged(_ sender: UITextField) {
guard let text = sender.text else { return }
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
// get thousands separator
let thousandsSeparator = formatter.groupingSeparator ?? ","
// strip thousands separators out
let stripped = String(text.filter { return String([=11=]) != thousandsSeparator })
// see if decimal place found, and if so, set fractional digits accordingly
let decimalSeparator = formatter.decimalSeparator ?? "."
var fractionalDigits: Int?
if let decimalSeparatorIndex = text.range(of: decimalSeparator)?.lowerBound {
fractionalDigits = text[decimalSeparatorIndex...].count(of: "0123456789")
formatter.minimumFractionDigits = fractionalDigits!
}
guard
let number = formatter.number(from: stripped),
var result = formatter.string(from: number)
else {
// do whatever is appropriate if string isn't a number at all
return
}
// re-add trailing decimal place only if decimal separator was found, but no fractional digits were
if fractionalDigits == 0 {
result += decimalSeparator
}
// update text field
sender.text = result
}
注意,使用这个小扩展:
extension StringProtocol {
func count(of string: String) -> Int {
return reduce(0) { [=12=] + (string.contains() ? 1 : 0) }
}
}
您可以解决许多其他改进。例如,如果用户在编辑时不在文本字段的末尾,这将重置 selectedTextRange
。您可能还应该实施 shouldChangeCharactersIn
以确保您根本无法在 stripped
会失败的地方输入值。等等
但希望这说明了一种捕获文本输入并使用格式化的十进制数字更新结果的方法。
对于 Swift 2 版本,请参阅 previous revision of this answer。
我有一个 UILabel
来显示输入文本(有十进制数字)。我想要做的是,UILabel
文本可以根据语言环境显示。例如-
"1234.56" should be shown as "1,234.56" for US locale, "1.234,56" for DE (Germany) locale and so on.
以下是我为实现这一目标所做的工作 -
NSNumberFormatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
NSNumberFormatter.locale = NSLocale(localeIdentifier: language)
NSNumberFormatter.maximumFractionDigits = 16
let displayVal: Double = NSNumberFormatter.numberFromString(displayText.text!).doubleValue
displayText.text = NSNumberFormatter.stringFromNumber(displayVal)
其中 displayText
是显示输入的 UILabel
。
它工作正常,直到 4 位数字,即“1234”显示为“1,234”(对于美国语言环境)。但是一旦添加了第 5 位数字,nil
就返回了 displayVal
常量变量。
我可以从函数定义中猜到格式化 displayText
文本字符串失败,当 numberFromString
尝试按照美国语言环境格式化它时可能是“1,2345”但失败了这不符合美国语言环境格式。
谁能提出解决此问题的方法或更好的实施方法?
您需要确保数字格式化程序与您传递给它的字符串匹配。如果有任何不匹配,它将变为 return nil,并且 doubleValue 调用将变为 return 0.
如果您有针对美国格式化的字符串,使用逗号的分组分隔符,那么您应该将数字格式化程序的 groupingSeparator
属性 设置为逗号。然后格式化程序应该处理像“1,234”这样的输入字符串。正如您所说,“1,2345”不是用于显示数字的普通美国格式。
您可能还需要更改 groupingSize 设置(如果我没记错的话,字符串“1,2345”的 groupingSize 为 4。
您解析的字符串来自哪里?你知道他们使用什么语言环境吗?用户是否在使用 en-US
语言环境设置的设备上输入“1,2345”?如果是,为什么?这不是美国英语的正常格式。
您可以执行类似以下操作,即去掉任何千位分隔符,从中获取一个数字,然后使用千位分隔符重新格式化:
@IBAction func didEditingChanged(_ sender: UITextField) {
guard let text = sender.text else { return }
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
// get thousands separator
let thousandsSeparator = formatter.groupingSeparator ?? ","
// strip thousands separators out
let stripped = String(text.filter { return String([=10=]) != thousandsSeparator })
// now, re-insert them, if any
if let number = formatter.numberFromString(stripped) {
sender.text = formatter.stringFromNumber(number)
}
}
假设您将它连接到 "Editing Changed" 以便它不断更新,这会引入一些问题。例如,要输入尾随小数位,您可能必须手动检查并允许保留:
@IBAction func didEditingChanged(_ sender: UITextField) {
guard let text = sender.text else { return }
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
// get thousands separator
let thousandsSeparator = formatter.groupingSeparator ?? ","
// strip thousands separators out
let stripped = String(text.filter { return String([=11=]) != thousandsSeparator })
// see if decimal place found, and if so, set fractional digits accordingly
let decimalSeparator = formatter.decimalSeparator ?? "."
var fractionalDigits: Int?
if let decimalSeparatorIndex = text.range(of: decimalSeparator)?.lowerBound {
fractionalDigits = text[decimalSeparatorIndex...].count(of: "0123456789")
formatter.minimumFractionDigits = fractionalDigits!
}
guard
let number = formatter.number(from: stripped),
var result = formatter.string(from: number)
else {
// do whatever is appropriate if string isn't a number at all
return
}
// re-add trailing decimal place only if decimal separator was found, but no fractional digits were
if fractionalDigits == 0 {
result += decimalSeparator
}
// update text field
sender.text = result
}
注意,使用这个小扩展:
extension StringProtocol {
func count(of string: String) -> Int {
return reduce(0) { [=12=] + (string.contains() ? 1 : 0) }
}
}
您可以解决许多其他改进。例如,如果用户在编辑时不在文本字段的末尾,这将重置 selectedTextRange
。您可能还应该实施 shouldChangeCharactersIn
以确保您根本无法在 stripped
会失败的地方输入值。等等
但希望这说明了一种捕获文本输入并使用格式化的十进制数字更新结果的方法。
对于 Swift 2 版本,请参阅 previous revision of this answer。