0

Say I have a string "45 minutes. 5 minutes", and I want to find the range of the "5 minutes".

let example = "45 minutes. 5 minutes"
let range = example.range(of: "5 minutes")

Instead of returning a range matching the standalone "5 minutes", it matches the end of the "45".

let example = "45 minutes. 5 minutes"
                |–––––––| // ← This is the match
                           |–––––––| // ← This is what I am after

So how would I find the range of what is technically the second occurrence of the string.

Will
  • 4,942
  • 2
  • 22
  • 47

2 Answers2

1

You could search backwards

let example = "45 minutes. 5 minutes"
let range = example.range(of: "5 minutes", options: .backwards)

or with a little help of Regular Expression if the second occurrence is exactly the end of the string

let range = example.range(of: "5 minutes$", options: .regularExpression)

or with a word boundary specifier if it's not the end of the string

let range = example.range(of: "\\b5 minutes", options: .regularExpression)

Edit:

As you are apparently looking for the ranges of all matches – which you didn't mention in the question – you can do this with real Regular Expression

let example = "45 minutes. 5 minutes"
let regex = try! NSRegularExpression(pattern: "5 minutes")
let matches = regex.matches(in: example, range: NSRange(example.startIndex..., in: example))
    .compactMap{Range($0.range, in: example)}
vadian
  • 274,689
  • 30
  • 353
  • 361
  • Good idea! It's not quite as flexible as I need, so I came up with a different approach that'll I'll answer my own question with – Will Oct 05 '21 at 06:54
0

Figured it out!

I store matches as I find them in an array,

let previousMatches = [Range<String.Index>]()

Then as I search for a new match, I do this:

var myString = "45 minutes. 5 minutes"
var searchString = "5 minutes"
var searchRange: Range<String.Index>?
if let previousMatch = self.previousMatches.last {
    searchRange = previousMatch.upperBound ..< myString.endIndex
}
let match = myString.range(of: "5 minutes", range: searchRange)

If that runs twice, it gets both matches.

Will
  • 4,942
  • 2
  • 22
  • 47