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

时间:2019-02-22 16:21:29

标签: swift string range nsrange

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

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

但是,我可能要处理很长的文本,所以当我只需要第一行组成部分时,首先将 entire 字符串拆分为行组成部分似乎效率不高。因此,使用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作为参数(这对我来说实际上没有意义,因为它应被称为{{1} },而不是UnicodeScalarSet,但没关系...)。

我的问题是:

如何在不先将整个字符串切成薄片的情况下有效地实现这一点?

(不一定要使用CharacterSet方法,但似乎是一种方法。)

2 个答案:

答案 0 :(得分:2)

通过{p>可以获取String.Index中第一行的string范围

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

如果您需要将其作为NSRange,则

let nsRange = NSRange(range, in: string)

起到了作用。

答案 1 :(得分:1)

您可以使用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)