格式化货币 - Swift
Formatting Currency - Swift
我正在寻找满足以下条件的文本字段货币格式化程序:
- 它应该被格式化(逗号分隔)我正在打字
- 应允许小数点前 10 位和小数点后 2 位
- 它应该允许 (2)
的正则表达式
- 剪切时,光标应该停留在原处
- 当我们在货币中间输入时,光标不应该向左移动。
- 它应该支持正则表达式中的本地化(逗号和句点)。
我尝试了很多解决方案:
使用 NSCharacterSet
(这是最接近的,但由于在本地化过程中 .
和 ,
的互换,正则表达式在这里失败,我们也使用 .decimal
在此处键入以避免文本字段中的 $
)
class func checkTextField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let textBeforeEditing = textField.text else {
return true
}
if ((string == "0" || string == "") && (textField.text! as NSString).range(of: ".").location < range.location) {
return true
}
var currentPosition = 0
if let selectedRange = textField.selectedTextRange {
currentPosition = textField.offset(from: textField.beginningOfDocument, to: string == "" ? selectedRange.end : selectedRange.start)
}
let allowedCharacterSet = NSCharacterSet(charactersIn: "0123456789.").inverted
let filtered = string.components(separatedBy: allowedCharacterSet)
let component = filtered.joined(separator: "")
let isNumeric = string.replacingOccurrences(of: ",", with: "") == component
var textFieldString : String = ""
var numberWithoutCommas : String = ""
guard isNumeric else {
return false
}
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
textFieldString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
numberWithoutCommas = textFieldString.replacingOccurrences(of: ",", with: "")
let formattedNumberWithoutCommas = formatter.number(from: numberWithoutCommas)
guard let formattedNumber = formattedNumberWithoutCommas, var formattedString = formatter.string(from: formattedNumber) else {
textField.text = nil
return false
}
if string == "." && range.location == textField.text?.count {
formattedString = formattedString.appending(".")
}
textField.text = formattedString
currentPosition = getCursorPositionForTextField(string: string, cursorPosition: currentPosition, formattedString: formattedString, textBeforeEditing: textBeforeEditing)
handleTextFieldCursor(cursorPosition: currentPosition, textField: textField)
return false
}
使用 NumberFormatter
但光标移动到每个 cut/paste
结束
extension String {
func currencyInputFormatting() -> String {
var number: NSNumber!
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
var amountWithPrefix = self
// remove from String: "$", ".", ","
let regex = try! NSRegularExpression(pattern: "[^0-9]", options: .caseInsensitive)
amountWithPrefix = regex.stringByReplacingMatches(in: amountWithPrefix, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, self.characters.count), withTemplate: "")
let double = (amountWithPrefix as NSString).doubleValue
number = NSNumber(value: (double / 100))
guard number != 0 as NSNumber else {
return ""
}
return formatter.string(from: number)!
}
}
我花了将近一两天的时间寻找 100% 可行的解决方案,但无法解决。
任何帮助将不胜感激
编辑
在@denis_lor答案的帮助下,我已经非常接近解决方案,但仍然无法实现逗号与句点的互换。这是我更新的代码,我错过了什么吗?它适用于英语,但不适用于西班牙语。
class func checkTextField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let textBeforeEditing = textField.text else {
return true
}
if ((string == "0" || string == "") && (textField.text! as NSString).range(of: "\(NSLocalizedString("core_decimal_separator_symbol", comment: ""))").location < range.location) {
return true
}
var currentPosition = 0
if let selectedRange = textField.selectedTextRange {
currentPosition = textField.offset(from: textField.beginningOfDocument, to: string == "" ? selectedRange.end : selectedRange.start)
}
let allowedCharacterSet = NSCharacterSet(charactersIn: "0123456789\(NSLocalizedString("core_decimal_separator_symbol", comment: ""))").inverted
let filtered = string.components(separatedBy: allowedCharacterSet)
let component = filtered.joined(separator: "")
let isNumeric = string.replacingOccurrences(of: NSLocalizedString("core_thousand_separator_symbol", comment: ""), with: "") == component
var textFieldString : String = ""
var numberWithoutCommas : String = ""
guard isNumeric else {
return false
}
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
textFieldString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
numberWithoutCommas = textFieldString.replacingOccurrences(of: NSLocalizedString("core_thousand_separator_symbol", comment: ""), with: "")
let formattedNumberWithoutCommas = formatter.number(from: numberWithoutCommas)
guard let formattedNumber = formattedNumberWithoutCommas, var formattedString = formatter.string(from: formattedNumber) else {
textField.text = nil
return false
}
if string == NSLocalizedString("core_decimal_separator_symbol", comment: "") && range.location == textField.text?.count {
formattedString = formattedString.appending(NSLocalizedString("core_decimal_separator_symbol", comment: ""))
}
textField.text = formattedString
currentPosition = getCursorPositionForTextField(string: string, cursorPosition: currentPosition, formattedString: formattedString, textBeforeEditing: textBeforeEditing)
handleTextFieldCursor(cursorPosition: currentPosition, textField: textField)
return false
}
好的,看来您的问题可以通过第一轮实施您的第一个解决方案来解决,您只需要考虑 ,
和 .
的本地化。这很简单,您可以通过多种不同的方式实现它,但重要的是您的应用程序已本地化,例如使用两种使用不同符号处理小数和千位的语言(假设这些语言是英语和意大利语) ):
- [en] 语言用
,
分隔小数,用 .
分隔千位
- [it] 语言用
.
分隔小数,用 ,
分隔千位
A) 你可以做的是创建一个 Localizable.strings
文件,然后本地化你的项目,让我们以英语和意大利语为例。为此,请在此处添加语言。
B) 然后转到您的 Localizable.strings
文件并 localize
它用于您支持的语言(例如英语和意大利语),就像这张为德语和英语所做的图像
您现在将得到两个 Localizable.strings,一个用于英语,一个用于意大利语:
Localizable.strings(英文)
core_decimal_separator_symbol = ",";
core_thousand_separator_symbol = ".";
Localizable.strings(意大利语)
core_decimal_separator_symbol = ".";
core_thousand_separator_symbol = ",";
C) 在您的代码中,您需要处理的任何地方,例如,您的 小数分隔符 ,而不是硬编码,您可以这样做:
removeDecimalSeparator = numberAsString.replacingOccurrences(of: NSLocalizedString("core_decimal_separator_symbol", comment: ""), with: "")
因此,每当您的应用本地化为英语时,例如,此代码将转换为:
removeDecimalSeparator = numberAsString.replacingOccurrences(of: ",", with: "")
例如,当您的应用程序本地化为意大利语时,此代码将转换为:
removeDecimalSeparator = numberAsString.replacingOccurrences(of: ".", with: "")
总而言之:考虑到我们在此答案中的 Localizable.strings,将这些视为示例。只是为了向您展示如何通过在您的应用程序中使用本地化以不同的方式针对不同的语言处理一些符号。
我正在寻找满足以下条件的文本字段货币格式化程序:
- 它应该被格式化(逗号分隔)我正在打字
- 应允许小数点前 10 位和小数点后 2 位
- 它应该允许 (2) 的正则表达式
- 剪切时,光标应该停留在原处
- 当我们在货币中间输入时,光标不应该向左移动。
- 它应该支持正则表达式中的本地化(逗号和句点)。
我尝试了很多解决方案:
使用
NSCharacterSet
(这是最接近的,但由于在本地化过程中.
和,
的互换,正则表达式在这里失败,我们也使用.decimal
在此处键入以避免文本字段中的$
)class func checkTextField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { guard let textBeforeEditing = textField.text else { return true } if ((string == "0" || string == "") && (textField.text! as NSString).range(of: ".").location < range.location) { return true } var currentPosition = 0 if let selectedRange = textField.selectedTextRange { currentPosition = textField.offset(from: textField.beginningOfDocument, to: string == "" ? selectedRange.end : selectedRange.start) } let allowedCharacterSet = NSCharacterSet(charactersIn: "0123456789.").inverted let filtered = string.components(separatedBy: allowedCharacterSet) let component = filtered.joined(separator: "") let isNumeric = string.replacingOccurrences(of: ",", with: "") == component var textFieldString : String = "" var numberWithoutCommas : String = "" guard isNumeric else { return false } let formatter = NumberFormatter() formatter.numberStyle = .decimal textFieldString = (textField.text! as NSString).replacingCharacters(in: range, with: string) numberWithoutCommas = textFieldString.replacingOccurrences(of: ",", with: "") let formattedNumberWithoutCommas = formatter.number(from: numberWithoutCommas) guard let formattedNumber = formattedNumberWithoutCommas, var formattedString = formatter.string(from: formattedNumber) else { textField.text = nil return false } if string == "." && range.location == textField.text?.count { formattedString = formattedString.appending(".") } textField.text = formattedString currentPosition = getCursorPositionForTextField(string: string, cursorPosition: currentPosition, formattedString: formattedString, textBeforeEditing: textBeforeEditing) handleTextFieldCursor(cursorPosition: currentPosition, textField: textField) return false }
使用
结束NumberFormatter
但光标移动到每个 cut/pasteextension String { func currencyInputFormatting() -> String { var number: NSNumber! let formatter = NumberFormatter() formatter.numberStyle = .currency formatter.maximumFractionDigits = 2 formatter.minimumFractionDigits = 2 var amountWithPrefix = self // remove from String: "$", ".", "," let regex = try! NSRegularExpression(pattern: "[^0-9]", options: .caseInsensitive) amountWithPrefix = regex.stringByReplacingMatches(in: amountWithPrefix, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, self.characters.count), withTemplate: "") let double = (amountWithPrefix as NSString).doubleValue number = NSNumber(value: (double / 100)) guard number != 0 as NSNumber else { return "" } return formatter.string(from: number)! } }
我花了将近一两天的时间寻找 100% 可行的解决方案,但无法解决。 任何帮助将不胜感激
编辑
在@denis_lor答案的帮助下,我已经非常接近解决方案,但仍然无法实现逗号与句点的互换。这是我更新的代码,我错过了什么吗?它适用于英语,但不适用于西班牙语。
class func checkTextField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let textBeforeEditing = textField.text else {
return true
}
if ((string == "0" || string == "") && (textField.text! as NSString).range(of: "\(NSLocalizedString("core_decimal_separator_symbol", comment: ""))").location < range.location) {
return true
}
var currentPosition = 0
if let selectedRange = textField.selectedTextRange {
currentPosition = textField.offset(from: textField.beginningOfDocument, to: string == "" ? selectedRange.end : selectedRange.start)
}
let allowedCharacterSet = NSCharacterSet(charactersIn: "0123456789\(NSLocalizedString("core_decimal_separator_symbol", comment: ""))").inverted
let filtered = string.components(separatedBy: allowedCharacterSet)
let component = filtered.joined(separator: "")
let isNumeric = string.replacingOccurrences(of: NSLocalizedString("core_thousand_separator_symbol", comment: ""), with: "") == component
var textFieldString : String = ""
var numberWithoutCommas : String = ""
guard isNumeric else {
return false
}
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
textFieldString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
numberWithoutCommas = textFieldString.replacingOccurrences(of: NSLocalizedString("core_thousand_separator_symbol", comment: ""), with: "")
let formattedNumberWithoutCommas = formatter.number(from: numberWithoutCommas)
guard let formattedNumber = formattedNumberWithoutCommas, var formattedString = formatter.string(from: formattedNumber) else {
textField.text = nil
return false
}
if string == NSLocalizedString("core_decimal_separator_symbol", comment: "") && range.location == textField.text?.count {
formattedString = formattedString.appending(NSLocalizedString("core_decimal_separator_symbol", comment: ""))
}
textField.text = formattedString
currentPosition = getCursorPositionForTextField(string: string, cursorPosition: currentPosition, formattedString: formattedString, textBeforeEditing: textBeforeEditing)
handleTextFieldCursor(cursorPosition: currentPosition, textField: textField)
return false
}
好的,看来您的问题可以通过第一轮实施您的第一个解决方案来解决,您只需要考虑 ,
和 .
的本地化。这很简单,您可以通过多种不同的方式实现它,但重要的是您的应用程序已本地化,例如使用两种使用不同符号处理小数和千位的语言(假设这些语言是英语和意大利语) ):
- [en] 语言用
,
分隔小数,用.
分隔千位
- [it] 语言用
.
分隔小数,用,
分隔千位
A) 你可以做的是创建一个 Localizable.strings
文件,然后本地化你的项目,让我们以英语和意大利语为例。为此,请在此处添加语言。
B) 然后转到您的 Localizable.strings
文件并 localize
它用于您支持的语言(例如英语和意大利语),就像这张为德语和英语所做的图像
您现在将得到两个 Localizable.strings,一个用于英语,一个用于意大利语:
Localizable.strings(英文)
core_decimal_separator_symbol = ",";
core_thousand_separator_symbol = ".";
Localizable.strings(意大利语)
core_decimal_separator_symbol = ".";
core_thousand_separator_symbol = ",";
C) 在您的代码中,您需要处理的任何地方,例如,您的 小数分隔符 ,而不是硬编码,您可以这样做:
removeDecimalSeparator = numberAsString.replacingOccurrences(of: NSLocalizedString("core_decimal_separator_symbol", comment: ""), with: "")
因此,每当您的应用本地化为英语时,例如,此代码将转换为:
removeDecimalSeparator = numberAsString.replacingOccurrences(of: ",", with: "")
例如,当您的应用程序本地化为意大利语时,此代码将转换为:
removeDecimalSeparator = numberAsString.replacingOccurrences(of: ".", with: "")
总而言之:考虑到我们在此答案中的 Localizable.strings,将这些视为示例。只是为了向您展示如何通过在您的应用程序中使用本地化以不同的方式针对不同的语言处理一些符号。