Bolo
Bolo

Reputation: 2778

How get the lastIndexof with swift 2.0

I have tried to implement a method lastIndexOf. My code

extension String {
    var length:Int {
        return self.characters.count
    }

    func indexOf(target: String) -> Int? {

        let range = (self as NSString).rangeOfString(target)

        guard range.toRange() != nil else {
            return nil
        }

        return range.location

    }
    func lastIndexOf(target: String) -> Int? {

        let range = (self as NSString).rangeOfString(target, options: NSStringCompareOptions.BackwardsSearch)

        guard range.toRange() != nil else {
            return nil
        }

        return self.length - range.location - 1

    }
}

IndexOf returns me 45

"11055010155031e146145257690278f95004eca3d9ea110038da71507".indexOf("1003")

but lastIndexOf 11

"11055010155031e146145257690278f95004eca3d9ea110038da71507".lastIndexOf("1003")

I am not sure where is my error

Thank for any help

Upvotes: 1

Views: 4437

Answers (1)

Martin R
Martin R

Reputation: 539795

Your lastIndexOf() method returns 11 because

return self.length - range.location - 1

computes the offset from the location where the substring was found to the last character of the string, in your case 57 - 45 - 1 = 11. If you change the return statement to

return range.location

then you will get 45 for both calls because the substring "1003" occurs only once in the larger string.

Note that you can compute the offsets without using NSString/NSRange:

extension String {
    func indexOf(target: String) -> Int? {
        if let range = self.rangeOfString(target) {
            return startIndex.distanceTo(range.startIndex)
        } else {
            return nil
        }
    }

    func lastIndexOf(target: String) -> Int? {
        if let range = self.rangeOfString(target, options: .BackwardsSearch) {
            return startIndex.distanceTo(range.startIndex)
        } else {
            return nil
        }
    }
}

This also works better for strings with characters outside of the "Basic Multilingual Plane" such as Emojis or "flags". Examples are

"abc😀def".indexOf("d")

where your method returns 5 instead of 4 or

"abc🇩🇪def".indexOf("d")

where your method returns 7 instead of 4.


Update for Swift 3:

extension String {
    func index(of target: String) -> Int? {
        if let range = self.range(of: target) {
            return characters.distance(from: startIndex, to: range.lowerBound)
        } else {
            return nil
        }
    }

    func lastIndex(of target: String) -> Int? {
        if let range = self.range(of: target, options: .backwards) {
            return characters.distance(from: startIndex, to: range.lowerBound)
        } else {
            return nil
        }
    }
}

Upvotes: 14

Related Questions