Swift 4中更简单的字符串切片

时间:2017-09-15 21:27:52

标签: swift string substring swift4

Swift 4改变了字符串的工作方式。但是,似乎更复杂,更不易阅读。任何人都可以简化这个例子(简单地将String的第三个字母作为字符串)? (除了拆分线外。)

let myString="abc"
let thirdLetter = String(myString[myString.index(myString.startIndex, offsetBy: 2)])

2 个答案:

答案 0 :(得分:6)

在Swift 4中,您可以使用StringmyString [Character]转换为Array(myString)。然后,您可以使用Int索引该数组,然后将[Character]转换为String

let myString = "abc"
let thirdLetter = String(Array(myString)[2])    // "c"
let firstTwo = String(Array(myString)[0..<2])   // "ab"

如果您要在String上执行大量操作,通常最好转换并将其保留为[Character]

注意:我已经重新设计了这一部分,试图避免编译器可能执行的任何缓存优化。现在每种方法只测量一次,并为每种方法保留一个运行总计。

转换为Array并使用Int建立索引很容易编写和读取,但它是如何执行的?为了回答这个问题,我在发布版本中测试了以下内容:

func time1(str: String, n: Int) -> (Double, String) {
    // Method 1: Index string with String.Index, convert to String

    let start = Date()
    let a = String(str[str.index(str.startIndex, offsetBy: n)])
    let interval = Date().timeIntervalSince(start)

    return (interval, a)
}

func time2(str: String, n: Int) -> (Double, String) {
    // Method 2: Convert string to array, index with Int, convert to String

    let start = Date()
    let a = String(Array(str)[n])
    let interval = Date().timeIntervalSince(start)

    return (interval, a)
}


func time3(str: String, n: Int) -> (Double, String) {
    // Method 3: Use prefix() and last(), convert to String

    let start = Date()
    let a = String(str.prefix(n + 1).last!)
    let interval = Date().timeIntervalSince(start)

    return (interval, a)
}

func time4(str: String, n: Int) -> (Double, String) {
    // Method 4: Use Leo Dabus' extensions
    // https://stackoverflow.com/q/24092884/1630618

    let start = Date()
    let a = str[n]
    let interval = Date().timeIntervalSince(start)

    return (interval, a)
}

func time5(str: String, n: Int) -> (Double, String) {
    // Method 5: Same as 2 but don't measure Array conversion time

    let arr = Array(str)

    let start = Date()
    let a = String(arr[n])
    let interval = Date().timeIntervalSince(start)

    return (interval, a)
}

func test() {
    for repetitions in [1, 10, 100, 1000] {
        var input = ""
        for _ in 0 ..< repetitions {
            input.append("abcdefghijklmnopqrstuvwxyz")
        }

        var t = [0.0, 0.0, 0.0, 0.0, 0.0]
        let funcs = [time1, time2, time3, time4, time5]

        for i in 0 ..< input.count {
            for f in funcs.indices {
                let (interval, _) = funcs[f](input, i)
                t[f] += interval
            }
        }

        print("For string length \(input.count):")
        for i in 0 ..< 5 {
            print(String(format: "Method %d time: %.8f", i + 1, t[i]))
        }
        print("")
    }
}

<强>结果:

For string length 26:
Method 1 time: 0.00108612
Method 2 time: 0.00085294
Method 3 time: 0.00005889
Method 4 time: 0.00002104
Method 5 time: 0.00000405

For string length 260:
Method 1 time: 0.00117570
Method 2 time: 0.00670648
Method 3 time: 0.00115579
Method 4 time: 0.00110406
Method 5 time: 0.00007111

For string length 2600:
Method 1 time: 0.09964919
Method 2 time: 0.57621503
Method 3 time: 0.09244329
Method 4 time: 0.09166771
Method 5 time: 0.00087011

For string length 26000:
Method 1 time: 9.78054154
Method 2 time: 56.92994779
Method 3 time: 9.02372885
Method 4 time: 9.01480001
Method 5 time: 0.03442019

<强>分析:

  1. 转换为数组非常昂贵,尤其是在数组大小增加时。
  2. 如果您可以保留转换后的[Character],则对其进行索引操作非常快。 (见方法5)
  3. 方法1,3和4的速度大致相同,因此请根据自己的个人喜好进行选择。

答案 1 :(得分:2)

您似乎正在尝试提取第三个字符。我会说

let c = myString.prefix(3).last

当然,它是一个可选角色,但您可以在闲暇时展开并在需要时强制转换为String。

prefix方法非常有价值,因为它需要一个Int而不是强迫你进入String.Index的狂野和古怪的世界。