Swift中NumberFormatter格式化货币TextField输入4位数值跳0问题
问题成因
- 千位分隔符字符不匹配:sk-SK地区的货币格式化使用**非断空格(Unicode编码U+00A0)**作为千位分隔符,和普通ASCII空格(U+0020)肉眼显示完全一致但编码不同。你手动输入的
"1 000"用的是普通空格,NumberFormatter无法将其识别为合法的千位分隔符,解析失败返回nil,最终走兜底逻辑得到0。你在Playground里替换普通空格可生效,是因为手动构造的字符串用的是普通空格,真实运行时formatter生成的分隔符是非断空格,仅替换普通空格的逻辑无法处理,所以会失效。 - 解析规则过于严格:
.currency类型的NumberFormatter默认开启严格解析,要求输入字符串完全匹配当前地区的货币格式,缺少小数位、分隔符不匹配等小问题都会导致解析失败。
修复方案
1. 调整NumberFormatter配置
首先放宽解析规则,减少不必要的解析失败:
let formatter = NumberFormatter() formatter.locale = Locale(identifier: "sk-SK") formatter.numberStyle = .currency formatter.currencySymbol = "" // 新增配置 formatter.isLenient = true // 开启宽松解析,兼容部分格式不匹配的输入 formatter.generatesDecimalNumbers = true // 直接生成Decimal类型,避免NSNumber转Decimal的精度损失
2. 统一清洗输入字符串
不要只替换普通空格,兼容所有类型的千位分隔符:
// 方案1:直接移除所有空白字符,适配所有空格类型的千位分隔符 let cleanedInput = newValue.components(separatedBy: .whitespaces).joined() // 方案2:针对性移除当前地区的千位分隔符,兼容性更强 if let groupingSeparator = formatter.groupingSeparator { cleanedInput = newValue.replacingOccurrences(of: groupingSeparator, with: "") } let number = formatter.number(from: cleanedInput)?.decimalValue ?? 0
3. 双向绑定逻辑适配
处理TextField的绑定逻辑,避免输入过程中格式跳变:
@State private var amount: Decimal = 0 var formattedAmount: Binding<String> { Binding( get: { formatter.string(for: amount) ?? "" }, set: { newValue in let cleaned = newValue.components(separatedBy: .whitespaces).joined() amount = formatter.number(from: cleaned)?.decimalValue ?? 0 } ) } // 调用示例 TextField("请输入金额", text: formattedAmount) .keyboardType(.decimalPad)
内容的提问来源于stack exchange,提问作者Konstantin.Efimenko
相关产品推荐
相关产品推荐

