如何在Swift中获取给定字符范围的完整行范围?

时间:2019-02-22 15:11:45

标签: swift string macos line-numbers

Apple有一个古老的示例,如何在给定特定字符范围的情况下获得整行的范围:

Counting Lines of Text

为了获得第一行的完整行范围,他们调用了以下 Objective-C 函数:

[string lineRangeForRange:NSMakeRange(0, 0)]

我试图在 Swift 中实现相同的功能,但是由于方法签名已更改,我无法使其工作:

string.lineRange(for: NSRange(location: 0, length: 0))

引发编译器错误:

  

Argument type 'NSRange' (aka '_NSRange') does not conform to expected type 'RangeExpression'

RangeExpression是一些我还不太了解的怪异协议。但是,我认为Range<Bound>符合要求,因此我尝试了以下操作:

let range = NSRange(location: 0, length: 0)
textView.string.lineRange(for: Range<Int>(range)!)

这次,我又遇到了另一个编译器错误:

  

Generic parameter 'R' could not be inferred

RRange中都找不到任何通用参数RangeExpression

这是怎么回事,我该如何使它起作用?

1 个答案:

答案 0 :(得分:2)

lineRange(for:)(基本上)期望范围为String.Index,而不是整数范围。这是一个简单的示例:

let string = "Line1\nLine2"

// Find the full range of the line containing the first "1":
if let range = string.range(of: "1") {
    let lineRange = string.lineRange(for: range)
    print(string[lineRange]) // Line1
}

实际参数是类型为R : RangeExpression, R.Bound == String.Index的通用参数,这意味着您还可以传递部分范围,例如string.startIndex.....<string.endIndex

Objective-C sample code

的Swift版本
NSString *string;
unsigned numberOfLines, index, stringLength = [string length];
for (index = 0, numberOfLines = 0; index < stringLength; numberOfLines++)
    index = NSMaxRange([string lineRangeForRange:NSMakeRange(index, 0)]);

将会

let string = "Line1\nLine2"

var index = string.startIndex
var numberOfLines = 0
while index != string.endIndex {
    let range = string.lineRange(for: index..<index)
    numberOfLines += 1
    index = range.upperBound
}

print(numberOfLines)

index..<index在这里扮演NSMakeRange(index, 0)的角色。

如果目的只是为了计数(或枚举)总行数,则可以使用

string.enumerateLines(invoking: { (line, _) in
    // ...
})

代替(比较How to split a string by new lines in Swift)。