格式化货币 - Swift

Posted

技术标签:

【中文标题】格式化货币 - Swift【英文标题】:Formatting Currency - Swift 【发布时间】:2019-04-18 11:52:21 【问题描述】:

我正在寻找满足以下条件的文本字段货币格式化程序:

    它应该被格式化(逗号分隔)我正在输入 小数点前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,但每次剪切/粘贴时光标都会移动到结束

    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

【问题讨论】:

当然,您必须使用您的代码来满足上述要求。但这里有几个有用的链接 1.***.com/questions/15217124/… 2.reddit.com/r/swift/comments/6d4krx/… 请发布代码而不是图片,除非您想在编译器代码中显示一些警告。 @denis_lor 请检查 【参考方案1】:

好的,看来您的问题可以通过对您的第一个解决方案进行第一轮实施来解决,您只需考虑,. 的本地化。这很容易,您可以通过多种不同的方式实现它,但重要的是您的应用程序已本地化,例如使用两种语言处理小数和具有不同符号的千位(假设这些语言是英语和意大利语) ):

[zh] 语言用, 处理小数分隔,用. 处理千位分隔符 [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 。只是为了向您展示如何通过在您的应用中使用本地化以不同的方式为不同的语言操作一些符号。

【讨论】:

谢谢,会试一试,很快就会回来 你是什么意思它不适用于西班牙语?在 ios 设备中使用西班牙语时,本地化字符串 core_decimal_separator_symbol 到达该代码后的值是多少?放置断点或执行 print(NSLocalized.....) 来检查值。确保您的应用项目使用两种语言(步骤 1),检查您有两个 Localizable.strings 一个用于英语,一个用于西班牙语(步骤 2)。签入西班牙语,你有你期望的符号值。 最后一件事是:你是在模拟器上这样尝试吗?如果是,要将设备语言设置为西班牙语,您必须编辑您的应用项目方案并将语言设置为西班牙语,然后在模拟器中运行项目。这是以特定语言运行模拟器的唯一方法。 我已经完成了所有这些,但我似乎仍然错过了在 iOS 中正确处理的一些东西。我的可本地化字符串在西班牙语中运行良好,而且我还在整个过程中放置​​了断点。它在英语中正常工作 如果您在使用西班牙语时打印出本地化字符串符号,您是否会从 NSLocalized... 结果中获得预期值?如果是,那么到底出了什么问题?

以上是关于格式化货币 - Swift的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Double 格式化为货币 - Swift 3

如何将 SKProduct 价格格式化为 Swift 货币字符串?

如何使用 Swift 在文本字段(从右到左)上输入货币格式?

如何使用 Swift 在文本字段(从右到左)上输入货币格式?

NSDecimalNumber 用于 Swift 中的货币精度 [重复]

使用 Swift 如何将字符串转换为数字