在我的代码中,我有一个用户通过文本字段设置的数字。
struct ContentView: View {
@State private var numberText: String = ""
var body: some View {
TextField("0", text: $numberText)
}
}
我喜欢将这个数字存储为双精度数。我知道以下方法:
// Option A
Double(numberText)
// Option B
try? Double(self, format: .number)
// Option C
(self as? NSString)?.doubleValue
// Option D
let formatStyle = FloatingPointFormatStyle<Double>(locale: locale)
let parseStrategy = FloatingPointParseStrategy(format: formatStyle, lenient: true)
let formatInput = try? parseStrategy.parse(self)
// Option E
Manually parse by removing the locale.groupingSeparator and by replacing the locale.decimalSeparator with a '.' and then parse it with Double().
该问题出现在以下场景中。这些是我的设置:
选项 A、B 和 C 不起作用,因为它们不会考虑区域设置。他们总是会尝试解析带有点“23.45”的字符串。所以选项 D 最接近,但如果我给它当前的语言环境。它考虑了荷兰地区。这意味着它期望
23,45
而不是 23.45
。但是键盘使用数字格式化程序的设置,因此它将正确显示点作为小数分隔符。这意味着用户将输入 23.45
,解析器将产生错误的数字。
extension String {
var doubleValue: Double? {
var string = self.trimmingCharacters(in: .whitespacesAndNewlines)
if let groupingSeparator = Locale.current.groupingSeparator {
string = string.replacingOccurrences(of: groupingSeparator, with: "")
}
if let decimalSeparator = Locale.current.decimalSeparator, decimalSeparator != "." {
string = string.replacingOccurrences(of: decimalSeparator, with: ".")
}
return Double(string)
}
}
新的
FormatStyle
API 似乎不支持设备的数字格式设置,而仅使用“区域”设置中设置的区域设置的默认值。
另一方面,旧的
NumberFormatter
确实正确地做到了这一点:
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
// locale is Locale.current by default. You can optionally set this to the local from @Environment(\.locale)
// formatter.locale = ...
print(formatter.number(from: "1,6"))
您还可以直接将
NumberFormatter
传递给 TextField
:
TextField("Foo", value: $value, formatter: someFormatter)