【问题标题】:Add / subtract characters as Int in Swift在 Swift 中将字符加/减为 Int
【发布时间】:2017-07-18 20:14:37
【问题描述】:

我需要实现一个算法,通过计算字符串的模来检查输入是否有效。

Kotlin 中的代码:

private val facteurs = arrayOf(7, 3, 1)

private fun modulo(s: String): Int {
    var result = 0
    var i = -1
    var idx = 0
    for (c in s.toUpperCase()) {
        val value:Int
        if (c == '<') {
            value = 0
        } else if (c in "0123456789") {
            value = c - '0'
        } else if (c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ") {
            value = c.toInt() - 55
        } else {
            throw IllegalArgumentException("Unexpected character: $c at position $idx")
        }
        i += 1
        result += value * facteurs[i % 3]
        idx += 1
    }
    return result % 10
}

这意味着对字符进行数学运算。

在 Swift 3 和 4 中是否有一种优雅的方式来做到这一点?

我尝试了一些类似这样的繁琐结构:

value = Int(c.unicodeScalars) - Int("0".first!.unicodeScalars)

但它甚至无法编译。 我目前正在使用带有 XCode9 的 Swift 4,但也欢迎 Swift3 回答。

【问题讨论】:

    标签: swift string character


    【解决方案1】:

    可以一起枚举字符串的unicodeScalars视图 使用运行索引,使用 switch/case 模式匹配, 并访问 unicode 标量的数字 .value

    func modulo(_ s: String) -> Int? {
        let facteurs = [7, 3, 1]
        var result = 0
        for (idx, uc) in s.uppercased().unicodeScalars.enumerated() {
            let value: UInt32
            switch uc {
            case "<":
                value = 0
            case "0"..."9":
                value = uc.value - UnicodeScalar("0").value
            case "A"..."Z":
                value = uc.value - UnicodeScalar("A").value + 10
            default:
                return nil
            }
            result += Int(value) * facteurs[idx % facteurs.count]
        }
        return result % 10
    }
    

    这可以与 Swift 3 和 4 一起编译。当然你也可以 throw 错误而不是返回 nil 无效输入。

    请注意"&lt;""0""9" 等。 在 switch 语句中从上下文推断为UnicodeScalar, 不是StringCharacter,因此是"0"..."9"(在这种情况下) 是 ClosedRange&lt;UnicodeScalar&gt;uc 可以匹配 那个范围。

    【讨论】:

    • 在 swift 4 中,您可以遍历字符串。
    • @DonovanKing:是的,但我想要unicodeScalars,而不是characters。这允许匹配一个范围,并对值进行计算。
    • 啊,我明白了……是的,这是一个更好的解决方案。投赞成票 +1
    • 比我写的要优雅得多。谢谢你。 +1。
    • 有什么好方法可以摆脱硬编码的55?我假设是将"A" 转换为10,"Z" 转换为36,等等。我猜value = uc.value - UnicodeScalar("A").value + 10
    【解决方案2】:

    这样的东西对我有用:

    "A".utf16.first! + 2 //comes out to 67
    

    小心强制展开“!”

    如果您需要标量值,您可以这样做

    "A".unicodeScalars.first!.value + 2
    

    更多阅读可以在这个here in the SPL上完成。

    对于c 字符类型值,您可以这样做:

    String(c).unicodeScalars.first!.value + 2
    

    这是一个修改函数的尝试:

    func modulo(s: String) -> Int? {
    var result = 0
    var factors = [7,3,1]
    for (i, c) in s.uppercased().characters.enumerated() {
        let char = String(c)
        var val: Int
        if char == "<" {
            val = 0
        } else if "0123456789".contains(char) {
            val = Int(char.unicodeScalars.first!.value - "0".unicodeScalars.first!.value)
        } else if "ABCDEFGHIJKLMNOPQRSTUVWXYZ".contains(char) {
            val = Int(char.unicodeScalars.first!.value - 55)
        } else {
            return nil
        }
    
           result += val * factors[(i) % 3]
        }
    
        return result % 10
    }
    

    这是在 swift 3...in 4 我相信你可以在不转换为字符的情况下迭代字符串

    【讨论】:

    • c 的类型是 Character,Xcode 说 'utf16' 由于 'internal' 保护级别而无法访问。
    • @Xvolks 好的,让我看看。
    • 而且二元运算符'-'不能应用于'Character.UnicodeScalarView.Element'(又名'Unicode.Scalar')和'Int'类型的操作数
    • @Xvolks 你在使用'-'之前得到了值吗?
    • let value = Int(c.unicodeScalars.first!.value) - 55 有效,但做这么简单的事情似乎有点矫枉过正......
    猜你喜欢
    • 2015-08-26
    • 2016-03-19
    • 1970-01-01
    • 2016-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-18
    • 2011-02-28
    相关资源
    最近更新 更多