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



我想更改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. 

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

无法将类型'(Unicode.Scalar) -> Bool' 的值转换为预期的参数类型 'Character

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

我的问题是:

如何在不先切整个字符串的情况下以有效的方式实现这一点?

(它不一定必须使用firstIndex(where:)方法,但似乎是要走的路。

string中第一行的String.Index范围

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

如果您需要将其作为NSRange那么

let nsRange = NSRange(range, in: string)

能解决问题。

您可以使用rangeOfCharacter,它返回字符串中集合中第一个字符的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)

最新更新