【问题标题】:Parse multiple doubles from string in Swift在 Swift 中从字符串中解析多个双精度数
【发布时间】:2019-01-04 06:44:02
【问题描述】:

在 Swift 中从字符串(在 UITextView 中输入)解析多个双精度并将它们放入双精度数组中的最简单/最干净的方法是什么?

假设用户输入“23.4 45 16.997 -32”。当他进入它时,我想要

doubleArray[0] = 2
doubleArray[0] = 23
doubleArray[0] = 23.
doubleArray[0] = 23.4
doubleArray[1] = 4
doubleArray[1] = 45

等等

我有

var dataArray = [""]
dataArray = inputString.components(separatedBy: " ")

它可以很好地将数据分成一个字符串数组,然后我可以将每个字符串转换为双精度数。但是有没有更简洁更简洁的方式呢?

另外,有没有一种方法可以轻松地实时验证进入 UITextView 的数据?例如,条目中不允许有多个小数点或负号,不能有字母等?

我现在正在使用

let decimalPoint = NSLocale.current.decimalSeparator! as String
let validChars : Set<Character> = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "-", decimalSeparator[0], " "]  

validChar = Set(inputString).isSubset(of: validChars)
If !validChar {
    inputString.deleteBackward()
    //display Error Message
}

当然,这还需要确保没有小数点或负号……等等。所有简单的步骤,但没有更简单的东西吗?!? (这也大大简化了 - 我实际上有特定的错误消息,例如“只允许一个小数分隔符”、“无效字符”等)

(我也曾在其他情况下使用过 NSNumber,但不确定如何/是否可以在这里使用它。)

我觉得我正在尝试重新发明轮子......

【问题讨论】:

标签: ios swift


【解决方案1】:

结合 Leo 和 Martin 的答案:

let arrayOfDoubles = "This costs US$ 7.99"
  .components(separatedBy:.whitespacesAndNewlines)
  .compactMap{Double($0)}

应该工作和处理多种空白,如空格、不间断空格、制表符和换行符。

根据 Martin R,它不会处理区域设置的不同数字格式。

您可以在组合中添加一个 NumberFormatter:

let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = Locale(identifier: "de")

let arrayOfDoubles = "7 3,4 12,2 9 2,3"
    .components(separatedBy:.whitespacesAndNewlines)
    .compactMap{ formatter.number(from: $0).map { $0.doubleValue } }

print(arrayOfDoubles)

(上面的示例是为处理德语格式的数字而编写的,使用逗号小数分隔符。)

但是,如果您正在处理用于向服务器发送/接收的固定数字格式,则可能无关紧要。

【讨论】:

  • @MartinR,你是德国人,对吧?你知道Double.init?(String:) 是否使用“,”小数分隔符处理欧洲格式的小数吗?我希望如此,但我不确定。
  • 不,它没有。您需要一个 NumberFormatter 或一个 Scanner(具有适当设置的语言环境)。
【解决方案2】:

您可以继承UITextView 并覆盖textViewDidChange 方法,如下所示:

import UIKit

class NumbersTextView: UITextView, UITextViewDelegate {
    override func didMoveToSuperview() {
        delegate = self
    }
    func textViewDidChange(_ textView: UITextView) {
        // avoids a break line as the first character
        if text == "\n" {
            text = ""
            return
        }
        // avoids more than one period in a row
        if text.hasSuffix("..") {
            text!.removeLast()
        }
        // removes all invalid characters
        text!.removeAll {
            !("0"..."9" ~= $0) &&
            $0 != "\n" &&
            $0 != "."
        }
        // then check if the string ends in newLine
        // filter the doubles
        // map them into strings
        // join the numbers with newline separator
        if text.hasSuffix("\n") {
            text = text.byWords
                .compactMap { Double($0) }
                .map{ String($0) }
                .joined(separator: "\n")
            // adds the line break back to the string
            text! +=  "\n"
        }
    }

}

extension StringProtocol where Index == String.Index {
    var byWords: [SubSequence] {
        var byWords: [SubSequence] = []
        enumerateSubstrings(in: startIndex..., options: .byWords) { _, range, _, _ in
            byWords.append(self[range])
        }
        return byWords
    }
}

【讨论】:

  • 如果您需要根据 Martin R 在 cmets 上提到的用户区域设置允许使用不同的小数分隔符,您可以使用 NumberFormatter dropbox.com/s/2tlxnjraf32wedt/Number%20List.zip?dl=1
  • 按照 Martin 的建议,您的 byWords 扩展与使用 .components(separatedBy:.whitespacesAndNewlines) 相比有什么优势?他的方法似乎更简单。
  • @DuncanC 它也会删除标点符号
  • 明白了。对于您使用标点符号解析句子的情况,这将很有用。从单词末尾删除句点或逗号但如果它们是小数分隔符则保留它们是否足够聪明?
  • 是的,它会在像 25.0 这样的情况下留下句号,它将它标识为一个数字(单词)。
猜你喜欢
  • 2012-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-21
  • 2010-11-27
相关资源
最近更新 更多