swiftstringrangensrange

Swift: Get the range of the first line in a String?


I would like to change the formatting of the first line of text in an NSTextView (give it a different font size and weight to make it look like a headline). Therefore, I need the range of the first line. One way to go is this:

guard let firstLineString = textView.string.components(separatedBy: .newlines).first else {
    return
}
let range = NSRange(location: 0, length: firstLineString.count)

However, I might be working with quite long texts so it appears to be inefficient to first split the entire string into line components when all I need is the first line component. Thus, it seems to make sense to use the firstIndex(where:) method:

let firstNewLineIndex = textView.string.firstIndex { character -> Bool in
    return CharacterSet.newlines.contains(character)
}
// Then: Create an NSRange from 0 up to firstNewLineIndex. 

This doesn't work and I get an error:

Cannot convert value of type '(Unicode.Scalar) -> Bool' to expected argument type 'Character'

because the contains method accepts not a Character but a Unicode.Scalar as a parameter (which doesn't really make sense to me because then it should be called a UnicodeScalarSet and not a CharacterSet, but nevermind...).

My question is:

How can I implement this in an efficient way, without first slicing the whole string?

(It doesn't necessarily have to use the firstIndex(where:) method, but appears to be the way to go.)


Solution

  • A String.Index range for the first line in string can be obtained with

    let range = string.lineRange(for: ..<string.startIndex)
    

    If you need that as an NSRange then

    let nsRange = NSRange(range, in: string)
    

    does the trick.