Reputation: 2778
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
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