如何获取字符串中第一行的范围?

How to get the range of the first line in a string?

我想更改 NSTextView 中第一行文本的格式(为其设置不同的字体大小和粗细,使其看起来像标题)。因此,我需要第一行的范围。一种方法是:

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

但是,我可能正在处理很长的文本,因此当我只需要第一行组件时,首先将 整个 字符串拆分为行组件似乎效率低下。因此,使用 firstIndex(where:) 方法似乎是有意义的:

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

这不起作用,我得到一个错误:

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

因为 contains 方法不接受 Character 而是接受 Unicode.Scalar 作为参数(这对我来说没有意义,因为它应该被称为 UnicodeScalarSet 而不是 CharacterSet,但没关系...)。

我的问题是:

如何在不首先对整个字符串进行切片的情况下以有效的方式实现它?

(不一定要使用 firstIndex(where:) 方法,但似乎是可行的方法。)

您可以使用 rangeOfCharacter,其中 returns 字符串中一组字符的 Range<String.Index>

extension StringProtocol where Index == String.Index {
    var partialRangeOfFirstLine: PartialRangeUpTo<String.Index> {
        return ..<(rangeOfCharacter(from: .newlines)?.lowerBound ?? endIndex)
    }
    var rangeOfFirstLine: Range<Index> {
        return startIndex..<partialRangeOfFirstLine.upperBound
    }
    var firstLine: SubSequence {
        return self[partialRangeOfFirstLine]
    }
}

你可以这样使用它:

var str = """
    some string 
    with new lines
"""
var attributedString = NSMutableAttributedString(string: str)
let firstLine = NSAttributedString(string: String(str.firstLine))
// change firstLine as you wish

let range = NSRange(str.rangeOfFirstLine, in: str)
attributedString.replaceCharacters(in: range, with: firstLine)

string中第一行的String.Index范围可以用

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

如果您需要 NSRange 那么

let nsRange = NSRange(range, in: string)

成功了。