0

I want to find the first occurrence of string starting at given index.

Based on this answer I have created following function:

func index(of string: String, from startIndex: String.Index? = nil, options: String.CompareOptions = .literal) -> String.Index? {
    if let startIndex = startIndex {
        return range(of: string, options: options, range: startIndex ..< string.endIndex, locale: nil)?.lowerBound
    } else {
        return range(of: string, options: options, range: nil, locale: nil)?.lowerBound
    }
}

unfortunately, the part with the index doesn't work.

For example following code returns nil instead of 3:

let str = "test"
str.index(of: "t", from: str.index(str.startIndex, offsetBy: 1))
Community
  • 1
  • 1
Daniel
  • 20,420
  • 10
  • 92
  • 149

1 Answers1

2

You are limiting the search to the wrong range. string.endIndex should be self.endIndex (or just endIndex).

Further remarks:

  • range: nil and locale: nil can be omitted because those parameters have default values.

  • String.Index can be shortened to Index inside a String extension method, similarly for String.CompareOptions.

  • I would not call the optional parameter startIndex as that causes confusion with the startIndex property of String.

Putting it all together:

extension String {
    func index(of string: String, from startPos: Index? = nil, options: CompareOptions = .literal) -> Index? {
        if let startPos = startPos {
            return range(of: string, options: options, range: startPos ..< endIndex)?.lowerBound
        } else {
            return range(of: string, options: options)?.lowerBound
        }
    }
}

or alternatively

extension String {
    func index(of string: String, from startPos: Index? = nil, options: CompareOptions = .literal) -> Index? {
        let startPos = startPos ?? startIndex
        return range(of: string, options: options, range: startPos ..< endIndex)?.lowerBound
    }
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382