16

I am using the following code to get a String substring from an NSRange:

func substring(with nsrange: NSRange) -> String? {
    guard let range = Range.init(nsrange)
        else { return nil }
    let start = UTF16Index(range.lowerBound)
    let end = UTF16Index(range.upperBound)
    return String(utf16[start..<end])
}

(via: https://mjtsai.com/blog/2016/12/19/nsregularexpression-and-swift/)

When I compile with Swift 4 (Xcode 9b4), I get the following errors for the two lines that declare start and end:

'init' is unavailable
'init' was obsoleted in Swift 4.0

I am confused, since I am not using an init.

How can I fix this?

koen
  • 5,383
  • 7
  • 50
  • 89

2 Answers2

31

Use Range(_, in:) to convert an NSRange to a Range in Swift 4.

extension String {
    func substring(with nsrange: NSRange) -> Substring? {
        guard let range = Range(nsrange, in: self) else { return nil }
        return self[range]
    }
}
Charles Srstka
  • 16,665
  • 3
  • 34
  • 60
  • 1
    Xcode forces me to fix the code as follows: `func substring(with nsrange: NSRange) -> String? { guard let range = Range(nsrange, in: self) else { return nil } return String(self[range]) }` – koen Aug 02 '17 at 00:31
  • 1
    If you make the function return a Substring instead of a String, you won't have to convert the result. – Charles Srstka Aug 02 '17 at 00:34
  • Ah, I didn't realize Substring is a type, I thought it was a typo. – koen Aug 02 '17 at 01:19
  • 1
    Substring is a slice type. What that means is that it holds a reference to the original string, as well as the range that the substring represents. The advantage of a slice is that you don't have to make a copy of the data the way you would if you were returning a new String, so performance is better. – Charles Srstka Aug 02 '17 at 02:59
5

With Swift 4 we can get substrings this way.

  1. Substring from index

    let originStr = "Test"
    let offset = 1
    let str = String(originStr.suffix(from: String.Index.init(encodedOffset: offset)))
    
  2. Substring to index

    let originStr = "Test"
    let offset = 1
    String(self.prefix(index))
    
Nathan Tuggy
  • 2,237
  • 27
  • 30
  • 38