Search code examples
swiftnsstringnsrange

Getting Error with NSStringEnumerationOptions.ByWords - Swift 4.2


I am trying to add this Extension to my code in order to enumerate substrings by words. The source of this code was dated 2015, so this is apparently an earlier version of Swift. I'm using Swift4.2 and I can't figure out how to properly update the code in the line identified below with a note.

extension String {
    func words() -> [String] {

        let range = Range<String.Index>(start: self.startIndex, end: self.endIndex) // THIS LINE CAUSES ERROR
        var words = [String]()

        self.enumerateSubstringsInRange(range, options: NSStringEnumerationOptions.ByWords) { (substring, _, _, _) -> () in
            words.append(substring)
        }

        return words
    }
}

I initially get this Error: Incorrect argument labels in call (have 'start:end:', expected '_:in:')

I follow the "Fix" prompt and it changes the line to this:

let range = Range<String.Index>(self.startIndex, in: self.endIndex)

Then, I get this Error with no Fix suggestion:

Cannot convert value of type 'String.Index' to expected argument type 'NSRange' (aka '_NSRange')

The Errors are probably due to a Swift version update and I can't figure out the proper way to write this line.


Solution

  • The enumerate substrings in range method syntax has changed a bit since Swift3:

    The new declaration:

    func enumerateSubstrings(in range: R, options opts: String.EnumerationOptions = default, _ body: @escaping (String?, Range, Range, inout Bool) -> Void) where R : RangeExpression, R.Bound == String.Index

    extension String {
        func words() -> [String] {
            var words = [String]()
            enumerateSubstrings(in: startIndex..., options: .byWords) { substring, _, _, _ in
                words.append(substring!)
            }
            return words
        }
    }
    

    "abc def".words()  //  ["abc", "def"]
    

    Note that in Swift 4 or later you should extend StringProtocol instead of the type String itself to support Substrings as well. You can check how to implement it at the answer I posted here