An Introduction to Regular Expressions | Ray Wenderlich

This introduction to regular expressions teaches you the basics of regular expressions and how to use them.

This is a companion discussion topic for the original entry at

Just wanted to thank you for the tutorial. It’s awesome.
Also thank you for highligtMatches functions it’s toooo goood.
On my own could not have made it. You guys rocks :+1:t2:

Cheers. Nanu Jogi

1 Like

@nanujogi Really glad to hear it helped so much. Take care and keep up the good work! :]

Hello, thank you for really great tutorial for iOS beginners! :slight_smile: Maybe I have find bug in function listGroups(). I have tried it in Playground this way:

let person = "54 male Russell Crowe"
listGroups(for: "([0-9]+)\\s?(male|female)?\\s?", inString: person)

let person2 = "54 Sandra Bullock"
listGroups(for: "([0-9]+)\\s?(male|female)?\\s?", inString: person2)

By the second usage, Playground wrote: Fatal error: Unexpectedly found nil while unwrapping an Optional value because (male|female)? was return nil for let range = Range(match.range(at: group), in: string)

I have changed
let range = Range(match.range(at: group), in: string)!


if let range = Range(match.range(at: group), in: string) {
} else {

Is it correct reasoning? I am programming in PHP and actually reading iOS Apprentice.

@tomelliott Can you please help with this when you get a chance? Thank you - much appreciated! :]

Hi @internetstream, you are right that the listGroups function won’t work in the example above.

The reason is because your regex contains the group (male|female)?, which is matched zero or more times. So when the text ‘male’ or ‘female’ is not present in the text, the regex engine is returning a capture group with a length of 0 and a location of NSNotFound.

You are also correct that guarding against this using if let will work. Although if your case I think I would also make sure to specifically guard against the location being NSNotFound as well.

Finally, one thing I should probably mention as well if you want to make this generic… The result of NSRegularExpression.matches(in:options:range:) returns the regex match as the first element in the array, and any Groups matched from element 1 onwards. So you should modify the function to start from index 1 not 0 if you only want groups.

I’ve tidied up ViewController.listGroups(for:inString:) to make it more generically applicable:

func listGroups(for pattern: String, inString string: String) -> [String] {
    guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else {
      return []

    let range = NSRange(string.startIndex..., in: string)
    let matches = regex.matches(in: string, options: [], range: range)

    var groupMatches: [String] = []
    for match in matches {
      let numberOfRangesInMatch = match.numberOfRanges
      for rangeIndex in 1..<numberOfRangesInMatch {
        let range = match.range(at: rangeIndex);
        if range.location != NSNotFound {
          if let rangeInString = Range(range, in: string) {

    return groupMatches

Hope that helps!

Hello @tomelliott, thanks a lot! Helped a lot. Have a nice day

This tutorial is more than six months old so questions are no longer supported at the moment for it. Thank you!