Find NSRanges of all substrings splitted by new lines

178 Views Asked by At

So I have this code finding Ranges substrings by splitting new lines:

let string = "hello\nhello"
let rangesSplittedByLines: [Range] = string.split(separator: "\n").compactMap {
    return string.range(of: $0)
}

But I need those ranges as NSRange. How would you get NSRange array of all substrings?

2

There are 2 best solutions below

0
vadian On BEST ANSWER

In the closure create an NSRange from Range<String.Index>

let string = "hello\nhello"
let rangesSplittedByLines: [NSRange] = string.split(separator: "\n").map {
    return NSRange(string.range(of: $0)!, in: string)
}

But there is another problem. The code returns [{0, 5}, {0, 5}] because range(of: returns always the range of the first match.

This fixes the problem, it slices the string by moving the start index to the position after the most recent match

let string = "hello\nhello"
var startIndex = string.startIndex
let rangesSplittedByLines: [NSRange] = string.split(separator: "\n").map {
    let subString = string[startIndex...]
    let swiftRange = subString.range(of: $0)!
    let nsRange = NSRange(swiftRange, in: string)
    startIndex = swiftRange.upperBound
    return nsRange
}

And there is no reason to bridge String to NSString explicitly.

But as you want nsranges anyway Regular Expression like in Martin’s answer is much more efficient.

0
Martin R On

Instead of splitting the string and “reconstructing” the ranges you can use a regular expression matching which returns the ranges directly. The [^\n]+ pattern matches one or more characters which are not the newline character. Example:

let string = "hello\nhello"

let regex = try! NSRegularExpression(pattern: #"[^\n]+"#)
let matches = regex.matches(in: string, range: NSRange(string.startIndex..., in: string))
let ranges = matches.map { $0.range }

print(ranges) // [{0, 5}, {6, 5}