【问题标题】:Why does swift substring with range require a special type of Range为什么带有范围的快速子字符串需要特殊类型的范围
【发布时间】:2017-07-06 23:30:45
【问题描述】:

考虑用这个函数构建一串随机字符:

func makeToken(length: Int) -> String {
    let chars: String = "abcdefghijklmnopqrstuvwxyz0123456789!?@#$%ABCDEFGHIJKLMNOPQRSTUVWXYZ"

    var result: String = ""
    for _ in 0..<length {
        let idx =  Int(arc4random_uniform(UInt32(chars.characters.count)))
        let idxEnd = idx + 1
        let range: Range = idx..<idxEnd
        let char = chars.substring(with: range)
        result += char
    }
    return result
}

这会在 substring 方法上引发错误:

Cannot convert value of type 'Range<Int>' to expected argument
type 'Range<String.Index>' (aka 'Range<String.CharacterView.Index>')

我很困惑为什么我不能简单地提供一个带有 2 个整数的 Range,以及为什么它让我绕道而行来制作一个 Range&lt;String.Index&gt;

所以我必须将 Range 创建更改为这种非常复杂的方式:

let idx =  Int(arc4random_uniform(UInt32(chars.characters.count)))
let start = chars.index(chars.startIndex, offsetBy: idx)
let end = chars.index(chars.startIndex, offsetBy: idx + 1)
let range: Range = start..<end

为什么 Swift 对我来说仅仅创建一个包含 2 个整数和半开范围运算符的范围还不够好? (..&lt;)

与“swift”形成鲜明对比,在javascript中我可以简单地做chars.substr(idx, 1)

【问题讨论】:

  • 因为字符没那么简单。它们并不都占用相同数量的内存。请参阅字符串文档中的Counting Characters 部分。

标签: swift string substring


【解决方案1】:

我建议将您的String 转换为[Character],以便您可以使用Int 轻松索引它:

func makeToken(length: Int) -> String {
    let chars = Array("abcdefghijklmnopqrstuvwxyz0123456789!?@#$%ABCDEFGHIJKLMNOPQRSTUVWXYZ".characters)

    var result = ""
    for _ in 0..<length {
        let idx = Int(arc4random_uniform(UInt32(chars.count)))
        result += String(chars[idx])
    }
    return result
}

【讨论】:

  • 我想你错过了我在字符串文字末尾的.characters。在 Swift 4 中,您将能够删除 .characters。在发布之前,我在 Xcode 和 Linux 上对此进行了测试。
  • @inorganik BTW,考虑到改进的String 类,仅使用Array("abc") 在Swift 4 中可以正常工作;)
【解决方案2】:

Swift 非常注意提供完全兼容 Unicode、类型安全、String 抽象。

在任意 Unicode 字符串中索引给定的Character 绝非易事。每个Character 是一个或多个Unicode 标量 的序列,它们(组合时)产生单个人类可读的字符。特别是,将所有这些复杂性隐藏在一个简单的基于Int 的索引方案后面可能会导致程序员错误的性能心理模型。

话虽如此,您始终可以将字符串转换为 Array&lt;Character&gt; 一次,以便轻松(且快速!)建立索引。例如:

let chars: String = "abcdefghijklmnop"
var charsArray = Array(chars.characters)
...
let resultingString = String(charsArray)

【讨论】:

  • 为什么 Swift 甚至需要考虑标量序列的复杂性?为什么我会关心这个?就我个人而言,我更喜欢 javascript 的方式 - 它隐藏了标量混乱,因为我永远不需要触摸它,我们 99.9% 的人也不需要
  • @inorganik 他们尝试非常努力做到 Unicode 正确、面向未来,默认情况下。实际上,Swift 是对我们隐藏标量“混乱”的人;)要明白我的意思,请在 28:00 左右check out this WWDC 2017 video。他们提供了一些很好的例子来说明为什么这在实践中很重要......
  • 谢谢保罗,我会去看看。
猜你喜欢
  • 1970-01-01
  • 2016-08-20
  • 2012-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多