Regular Expressions in Swift and iOS

I didn't actually planned on writing this post. However, things didn't go as I expected them to go. Today I was helping someone with Regular Expression which I thought was my forte and it still failed me. The regular expression exercise which I was arrogant about finishing in 10 minutes took me 2 hours to finish completely.

My this post is a blogification of all the frustration I went through and friendly bookmark for myself and other people who now or sometime in the future have to go through this situation.

In this post I will go through certain operations which we as developers have to frequently perform and will walk through examples as well. For all the examples I will assume the string I want to match or replace has following form

[zero_or_one_front_slash]#[any_number]#[one_two_or_no_star]

Examples,

  • #/100#*
  • #1#
  • #2000#**
  • #/3#*
  1. Finding matches (Reference)

    In the first example, given the input string and Regular Expression to match we will find and print all the matches for this combination. i.e. output all the substrings matching the given pattern

    Let's start by making utility function which takes parameters regex and input text and performs matches searching

    func matches(for regex: String, in text: String) -> [String] {
        do {
            let regex = try NSRegularExpression(pattern: regex)
            let results = regex.matches(in: text,
                                    range: NSRange(text.startIndex..., in: text))
            let finalResult = results.map {
                String(text[Range($0.range, in: text)!])
            }
            return finalResult
        } catch let error {
            print("invalid regex: \(error.localizedDescription)")
            return []
           }
        }
    

    For demo purpose, let our pattern and input string be following,

    let regex = "(#/{0,1}\\d{1,}#\\*{0,2})"
    // Mutable string because replaceMatches method on regex taken NSMutableString as an input
    var value: NSMutableString = "We are big now #1#**lot of sales#/1#* the money and cards #2#Rober Langdon and Ambra Vidal#/2#**."
    

    When we run this code, it will produce following output

    let allMatches = matches(for: regex, in: value as String)
    // Will print 
    //- 0 : "#1#**"
    //- 1 : "#/1#*"
    //- 2 : "#2#"
    //- 3 : "#/2#**"
    print(allMatches)
    

    What is that Regular Expression anyways?

    Let's go through the regular expression I mentioned above. Our task is not to be bothered about rest of the input string. Our only task is to apply regular expression pattern to input, check if matches and/or replace the string, that's it.

    1. First character # is obvious. It says that pattern must begin with #
    2. Second part /{0,1} says # must be followed by no or only one front- slash
    3. Third part \\d{1,} says next portion of string should be any digit with length of at least 1. If no digit is present, pattern is held invalid right there
    4. Next character # says, if digit is spotted it must immediately be followed by another # character
    5. Last pattern \\*{0,2} says our desired pattern must be terminated by no or at most 2 * characters

  2. Replacing matches
    In this part we will see with an example how we can replace detected sub string with another string

    Say we want to replace all the detected strings matching with pattern above with blank string,

    var value: NSMutableString = "We are big now #1#**lot of sales#/1#* the money and cards #2#Rober Langdon and Ambra Vidal#/2#**."
    let pattern = "(#/{0,1}\\d{1,}#\\*{0,2})"
    let regex = try? NSRegularExpression(pattern: pattern)
    regex?.replaceMatches(in: value, options: .reportProgress, range: NSRange(location: 0,length: value.length), withTemplate: "")
    // This will print We are big now lot of sales the money and cards Rober Langdon and Ambra Vidal.
    print(value)
    

    That was simple, but what if you want to re-use the detected string from an input. In that case there must be some way to utilize the detected pattern substring. This is where we will use special string $1.

    $1 in the regular expression represents the detected pattern in the input string which not surprisingly is the substring of the original input string. Since in the above example we only have one pattern, we will have $1 only. If you try to access $2 or any higher number, you will get blank string.

    We will get $1 for every detected pattern in the input string. However, if you have more than one pattern to detect in the input. (You can similarly enclose another pattern in round brackets as we have done above), variables $2, $3 and so on will be subsequently accessible in the app

    .
    var value: NSMutableString = "We are big now #1#**lot of sales#/1#* the money and cards #2#Rober Langdon and Ambra Vidal#/2#**."
    let pattern = "(#/{0,1}\\d{1,}#\\*{0,2})"
    let regex = try? NSRegularExpression(pattern: pattern)
    regex?.replaceMatches(in: value, options: .reportProgress, range: NSRange(location: 0,length: value.length), withTemplate: "aa$1aa")
    // Prints, We are big now aa#1#**aalot of salesaa#/1#*aa the money and cards aa#2#aaRober Langdon and Ambra Vidalaa#/2#**aa.
    print(value)
    

    In the above example, we wanted to append string aa to the beginning and end of detected pattern in the input string. However, you can do similar things with it such as duplicating detected pattern back to back and so on.

  3. Check if match exists
    You can also use regular expressions just to check if specified match exists or not. For this we will use the first function as an utility to achieve this task. The logic to check if match exists or not will simply return a boolean value specifying if for the given RegEx and input string, match exists or not

    func matchExists(for regex: String, in text: String) -> Bool {
        return matches(for: regex, in: text).count > 0
    }
    

    And this is all you have to do to perform just the pattern matching.

Please remember, sky is the limit when working with the Regular Expressions

Fun fact: while working on this post, I came across on-line interactive regular expressions checking website which is spectacular when it comes to being not sure about crafted expression and necessity to test it without compiling and running your code million times until everything works as expected. Definitely try it out!

Jayesh Kawli

I am a web and mobile developer working at Wayfair in Boston, MA. I come to learn so many things during course of life and I write about things which helped me and feel like they can help others too.

Subscribe to Fresh Beginning

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!