0

Swift 4 apparently has introduced a lot of new changes to String. I'm wondering if there is now a built-in method for finding all instances of a substring within a String.

Here's the kind of thing I'm looking for:

let searchSentence = "hello world, hello"
let wordToMatch = "hello"

let matchingIndexArray = searchSentence.indices(of: "wordToMatch")

'matchingIndexArray' would then be [0, 13]

jscs
  • 63,694
  • 13
  • 151
  • 195
Adam Bryant
  • 545
  • 3
  • 13

1 Answers1

0
import Foundation

let searchSentence = "hello world, hello"

var searchRange = searchSentence.startIndex..<searchSentence.endIndex
var ranges: [Range<String.Index>] = []

let searchTerm = "hello"

while let range = searchSentence.range(of: searchTerm, range: searchRange) {
    ranges.append(range)
    searchRange = range.upperBound..<searchRange.upperBound
}

print(ranges.map { "(\(searchSentence.distance(from: searchSentence.startIndex, to: $0.lowerBound)), \(searchSentence.distance(from: searchSentence.startIndex, to: $0.upperBound)))" })

outputs:

["(0, 5)", "(13, 18)"]
Charles Srstka
  • 16,665
  • 3
  • 34
  • 60
  • @JoshCaswell Nope; tried it in CodeRunner before posting it. It works in Swift 4 as written, and provides the output listed. – Charles Srstka Dec 26 '17 at 19:05
  • @JoshCaswell It's been in there at least since Swift 3, I think. Could you please remove the downvote, if that's the reason you put it there? – Charles Srstka Dec 26 '17 at 19:06
  • @JoshCaswell Fair enough. – Charles Srstka Dec 26 '17 at 19:07
  • @JoshCaswell One reason that the built-in version of `range(of:)` is better than casting to `NSString` is because you get a native `Range` which is an optional, instead of a non-optional `NSRange` using the decidedly un-Swifty `NSNotFound` sentinel. – Charles Srstka Dec 26 '17 at 19:09
  • @JoshCaswell it has been available at least since Swift 2 but it used to be written as `rangeOfString`. After Swift 3 the syntax changed to `range(of: String)` – Leo Dabus Dec 26 '17 at 19:16
  • Thank you for your answer @CharlesSrstka. Your solution isn't quite right though– say we're searching for the word "do" and the sentence contains the word "dodo". What will happen? – Adam Bryant Dec 26 '17 at 19:31
  • @AdamBryant You'd get (0..<2) and (2..<4), of course, because those are the instances of the substring within the string. Your question did not ask to search by whole words. – Charles Srstka Dec 26 '17 at 19:39
  • Fair enough. I’ll post a different question and hopefully it will be better formulated. There is a very practical need in actual software for highly efficient word matching, and it is in no way clear in any of the documentation what the solution is in Swift. – Adam Bryant Dec 26 '17 at 19:50