我还没有弄清楚如何在Swift中获得字符串的子字符串:

var str = “Hello, playground”
func test(str: String) -> String {
 return str.substringWithRange( /* What goes here? */ )
}
test (str)

我不能在Swift中创建一个范围。自动完成在游乐场不是超级有用的-这是它的建议:

return str.substringWithRange(aRange: Range<String.Index>)

我在Swift标准参考库中没有找到任何有用的东西。下面是另一个大胆的猜测:

return str.substringWithRange(Range(0, 1))

这:

let r:Range<String.Index> = Range<String.Index>(start: 0, end: 2)
return str.substringWithRange(r)

我看到了其他答案(在Swift字符串中查找字符索引),似乎表明,由于字符串是NSString的桥类型,“旧”方法应该工作,但不清楚如何-例如,这也不工作(似乎不是有效的语法):

let x = str.substringWithRange(NSMakeRange(0, 3))

想法吗?


当前回答

注意:@airspeedswift对这种方法的权衡提出了一些非常深刻的观点,特别是隐藏的性能影响。字符串不是简单的野兽,获得特定的索引可能需要O(n)时间,这意味着使用下标的循环可能是O(n²)。我警告过你了。

你只需要添加一个新的下标函数,它接受一个范围,并使用advancedBy()走到你想要的地方:

import Foundation

extension String {
    subscript (r: Range<Int>) -> String {
        get {
            let startIndex = self.startIndex.advancedBy(r.startIndex)
            let endIndex = startIndex.advancedBy(r.endIndex - r.startIndex)

            return self[Range(start: startIndex, end: endIndex)]
        }
    }
}

var s = "Hello, playground"

println(s[0...5]) // ==> "Hello,"
println(s[0..<5]) // ==> "Hello"

(这绝对应该是语言的一部分。请dupe rdar://17158813)

为了好玩,你还可以在索引上添加一个+运算符:

func +<T: ForwardIndex>(var index: T, var count: Int) -> T {
  for (; count > 0; --count) {
    index = index.succ()
  }
  return index
}

s.substringWithRange(s.startIndex+2 .. s.startIndex+5)

(我还不知道这个是否应该成为语言的一部分。)

其他回答

注意:@airspeedswift对这种方法的权衡提出了一些非常深刻的观点,特别是隐藏的性能影响。字符串不是简单的野兽,获得特定的索引可能需要O(n)时间,这意味着使用下标的循环可能是O(n²)。我警告过你了。

你只需要添加一个新的下标函数,它接受一个范围,并使用advancedBy()走到你想要的地方:

import Foundation

extension String {
    subscript (r: Range<Int>) -> String {
        get {
            let startIndex = self.startIndex.advancedBy(r.startIndex)
            let endIndex = startIndex.advancedBy(r.endIndex - r.startIndex)

            return self[Range(start: startIndex, end: endIndex)]
        }
    }
}

var s = "Hello, playground"

println(s[0...5]) // ==> "Hello,"
println(s[0..<5]) // ==> "Hello"

(这绝对应该是语言的一部分。请dupe rdar://17158813)

为了好玩,你还可以在索引上添加一个+运算符:

func +<T: ForwardIndex>(var index: T, var count: Int) -> T {
  for (; count > 0; --count) {
    index = index.succ()
  }
  return index
}

s.substringWithRange(s.startIndex+2 .. s.startIndex+5)

(我还不知道这个是否应该成为语言的一部分。)

在我写这篇文章的时候,没有一个扩展是完全兼容Swift 4.2的,所以这里有一个涵盖了我能想到的所有需求:

extension String {
    func substring(from: Int?, to: Int?) -> String {
        if let start = from {
            guard start < self.count else {
                return ""
            }
        }

        if let end = to {
            guard end >= 0 else {
                return ""
            }
        }

        if let start = from, let end = to {
            guard end - start >= 0 else {
                return ""
            }
        }

        let startIndex: String.Index
        if let start = from, start >= 0 {
            startIndex = self.index(self.startIndex, offsetBy: start)
        } else {
            startIndex = self.startIndex
        }

        let endIndex: String.Index
        if let end = to, end >= 0, end < self.count {
            endIndex = self.index(self.startIndex, offsetBy: end + 1)
        } else {
            endIndex = self.endIndex
        }

        return String(self[startIndex ..< endIndex])
    }

    func substring(from: Int) -> String {
        return self.substring(from: from, to: nil)
    }

    func substring(to: Int) -> String {
        return self.substring(from: nil, to: to)
    }

    func substring(from: Int?, length: Int) -> String {
        guard length > 0 else {
            return ""
        }

        let end: Int
        if let start = from, start > 0 {
            end = start + length - 1
        } else {
            end = length - 1
        }

        return self.substring(from: from, to: end)
    }

    func substring(length: Int, to: Int?) -> String {
        guard let end = to, end > 0, length > 0 else {
            return ""
        }

        let start: Int
        if let end = to, end - length > 0 {
            start = end - length + 1
        } else {
            start = 0
        }

        return self.substring(from: start, to: to)
    }
}

然后,你可以使用:

let string = "Hello,World!"

字符串。substring(from: 1, to: 7)得到你:ello,Wo

字符串。substring(to: 7)得到你:Hello,Wo

字符串。substring(from: 3)得到你:lo,World!

字符串。子字符串(从:1,长度:4)得到你:ello

字符串。substring(长度:4,到:7)得到你:o,Wo

更新的子字符串(from: Int?, length: Int)支持从零开始。

您可以使用substringWithRange方法。它有一个开头和结尾String.Index。

var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex, end: str.endIndex)) //"Hello, playground"

要更改开始和结束索引,请使用advancedBy(n)。

var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex.advancedBy(2), end: str.endIndex.advancedBy(-1))) //"llo, playgroun"

你也可以用NSRange使用NSString方法,但你必须确保你使用的是这样的NSString:

let myNSString = str as NSString
myNSString.substringWithRange(NSRange(location: 0, length: 3))

注意:正如JanX2提到的,第二个方法对于unicode字符串是不安全的。

如果你不关心性能……这可能是Swift 4中最简洁的解决方案

extension String {
    subscript(range: CountableClosedRange<Int>) -> String {
        return enumerated().filter{$0.offset >= range.first! && $0.offset < range.last!}
            .reduce(""){$0 + String($1.element)}
    }
}

它可以让你做这样的事情:

let myStr = "abcd"
myStr[0..<2] // produces "ab"

斯威夫特3.0

我决定有一个小乐趣与此,并产生一个扩展的字符串。我可能没有正确地使用截断这个词在我让函数实际做的事情中。

extension String {

    func truncate(from initialSpot: Int, withLengthOf endSpot: Int) -> String? {

        guard endSpot > initialSpot else { return nil }
        guard endSpot + initialSpot <= self.characters.count else { return nil }

        let truncated = String(self.characters.dropFirst(initialSpot))
        let lastIndex = truncated.index(truncated.startIndex, offsetBy: endSpot)

        return truncated.substring(to: lastIndex)
    }

}

let favGameOfThronesSong = "Light of the Seven"

let word = favGameOfThronesSong.truncate(from: 1, withLengthOf: 4)
// "ight"