How to convert Range in NSRange? [duplicate]
Asked Answered
M

1

30

I am updating my code in swift 3. Getting error in converting Range into NSRange. How to do that in swift 3 ?

func nsRange(_ range : Range<String.Index>) -> NSRange {
    let utf16from = String.UTF16View.Index(range.lowerBound, within: utf16)
    let utf16to   = String.UTF16View.Index(range.upperBound,   within: utf16)
    return NSRange(location: utf16.startIndex.distanceTo(utf16from), length: utf16from.distanceTo(utf16to))
}
Masaccio answered 5/4, 2017 at 13:45 Comment(2)
https://mcmap.net/q/23816/-nsrange-to-range-lt-string-index-gt has conversion methods for Swift 1.2, 2, and 3. โ€“ Architectural
... and for Swift 4. โ€“ Architectural
P
87

Xcode 11 โ€ข Swift 5.1

import Foundation

extension RangeExpression where Bound == String.Index  {
    func nsRange<S: StringProtocol>(in string: S) -> NSRange { .init(self, in: string) }
}

let string = "Hello USA ๐Ÿ‡บ๐Ÿ‡ธ !!! Hello World !!!"
if let nsRange = string.range(of: "Hello World")?.nsRange(in: string) {
    (string as NSString).substring(with: nsRange) //  "Hello World"
}

You can also create the corresponding nsRange(of:) method extending StringProtocol:

extension StringProtocol {
    func nsRange<S: StringProtocol>(of string: S, options: String.CompareOptions = [], range: Range<Index>? = nil, locale: Locale? = nil) -> NSRange? {
        self.range(of: string,
                   options: options,
                   range: range ?? startIndex..<endIndex,
                   locale: locale ?? .current)?
            .nsRange(in: self)
    }
    func nsRanges<S: StringProtocol>(of string: S, options: String.CompareOptions = [], range: Range<Index>? = nil, locale: Locale? = nil) -> [NSRange] {
        var start = range?.lowerBound ?? startIndex
        let end = range?.upperBound ?? endIndex
        var ranges: [NSRange] = []
        while start < end,
            let range = self.range(of: string,
                                   options: options,
                                   range: start..<end,
                                   locale: locale ?? .current) {
            ranges.append(range.nsRange(in: self))
            start = range.lowerBound < range.upperBound ? range.upperBound :
            index(range.lowerBound, offsetBy: 1, limitedBy: endIndex) ?? endIndex
        }
        return ranges
    }
}

let string = "Hello USA ๐Ÿ‡บ๐Ÿ‡ธ !!! Hello World !!!"

if let nsRange = string.nsRange(of: "Hello World") {
    (string as NSString).substring(with: nsRange) //  "Hello World"
}
let nsRanges = string.nsRanges(of: "Hello")
print(nsRanges)   // "[{0, 5}, {19, 5}]\n"
Piercy answered 5/4, 2017 at 14:8 Comment(3)
That swift 3 code is wrong check : developer.apple.com/documentation/swift/string.utf16view โ€“ Noemi
extension RangeExpression where Bound == String.Index { func nsRange<S: StringProtocol>(in string: S) -> NSRange { .init(self, in: string) } } crash in iOS 16 (is some cases) Fatal error: String index is out of bounds โ€“ Jacquetta
@HassanTaleb There is no way for this to happen if you use it properly. Fell free to open a new question with a minimal reproducible example โ€“ Piercy

© 2022 - 2024 โ€” McMap. All rights reserved.