简体   繁体   中英

Finding occurrences of String as NSRange from an NSString using Swift, result NSRange to be used in NSAttributedString

I am trying to find NSRange 's of several strings within an string.

In my following code, I use String.range(of: String, options: , Range) method to find Range , and convert to NSRange . this conversion fails when text contains multi-code unit unicode characters, such as emoji:

let findInString = "This #is a #tag #tag inten#sive🔦#search" // MAY CONTAINS EMOJIS
let findStrings = ["#is","#tag","#sive","#search"]
let result = NSMutableAttributedString(string: findInString)

for (index, stringToFind) in findStrings.enumerated() {

    var nextStartIndex = findInString.startIndex

    while let range = findInString.range(of: stringToFind, options: [.literal, .caseInsensitive], range: nextStartIndex..<findInString.endIndex) {

        let start = findInString.distance(from: findInString.startIndex, to: range.lowerBound)
        let length = findInString.distance(from: range.lowerBound, to: range.upperBound)

        result.addAttribute(NSLinkAttributeName, value: "\(index):", range: NSMakeRange(start, length))

        nextStartIndex = range.upperBound
    }

}

Question: Will it work If I use NSString.range() to find NSRange . I am trying this, but my following code have an error in range: part.

let findInNsString = findInString as NSString
while let range = findInNsString.range(of: stringToFind, options: [.literal, .caseInsensitive], range: nextStartIndex..<findInString.endIndex)

I need help to understand and correct the above error, thanks in advance.

Found the correct way to convert a Range to NSRange , thanks to MartinR for this answer

I was using the wrong way to convert Range to NSRange , here is the working code snippet with proper way to convert from Range to NSRange :

let findStrings = ["#is","#tag","#siØve","#search"]
let findInString = "This #is a #tag #tag inten#siØve🔦#search"
let result = NSMutableAttributedString(string: findInString)
let utf16 = findInString.utf16
for (index, stringToFind) in findStrings.enumerated() {

    var nextStartIndex = findInString.startIndex

    while let range = findInString.range(of: stringToFind, options: [.literal, .caseInsensitive], range: nextStartIndex..<findInString.endIndex) {

        // PROPER WAY TO CONVERT TO NSRange
        let from = range.lowerBound.samePosition(in: utf16)
        let start = utf16.distance(from: utf16.startIndex, to: from)
        let length = utf16.distance(from: from, to: range.upperBound.samePosition(in: utf16))

        result.addAttribute(NSLinkAttributeName, value: "\(index):", range: NSMakeRange(start, length))

        nextStartIndex = range.upperBound
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM