Regular Expressions in Switch Statements

Expression Patterns in Swift appear in switch statement case labels. The expression represented by the expression pattern is compared with the value of the switch statement input using the Swift standard library ~= operator. The matches succeeds if the ~= operator returns true. By default, the ~= operator compares two values of the same type using the == operator. It can also match an integer value with a range of integers in an Range object. The ~= operator can be extended to provide custom expression matching behavior.

In this post, we will extend the ~= operator to match the String type with regular expressions (specifically NSRegularExpression). Combined with bit of syntactic sugar, we will be able to write compact pattern expressions like this:

switch("apple"){
  case "appl": println("string")        
  case ~/"a..le": println("regex")  // Match!
  default: println("none")
}

//Output: regex

In this example, the switch statement matches the second case which is a regular expression a..pl.

Extending the ~= Operator

We can extend the ~= Operator to match NSRegularExpression:

func ~=(pattern: NSRegularExpression, str: NSString) -> Bool {
  return pattern.numberOfMatchesInString(str, options: nil, range: NSRange(location: 0,  length: str.length)) > 0
}

The pattern matching ~= operator is not commutative. A reverse matcher must be defined for cases where the input to the switch statement is a regular expression and is being compared to string via a case statement.

We can now introduce a regular expression in a switch statement to and check for matches:

switch("apple"){
  case "appl": println("string")
  case NSRegularExpression(pattern: "a..le", options: nil, error: nil): println("regex")
  default: println("none")
}

//Output: regex

Regex Creating Operator

Borrowing from Groovy et al., we can define a regex creating operator which accepts a string and returns a NSRegularExpression object (using default options, for now).

operator prefix ~/ {}

@prefix func ~/(pattern: String) -> NSRegularExpression {
  return NSRegularExpression(pattern: pattern, options: nil, error: nil)
}

This lets us create regex objects with the compact notation from the first example.

~/"\\wpple" ~= "apple is a fruit"     //Boolean: true

Note that the regex group \w is escaped in the string literal.

In Swift, custom prefix and postfix operators cannot specify precedence, requiring the use of parenthesis: (~/”a..pl”).numberOfMatchesInString(…)

Swift bits

While we wait for  Swift‘s documentation to get a tad more comprehensive, we’re capturing Swift nuances, patterns and gotchas as we uncover them. Expect this post to be updated frequently over the next several days.

Links, in no particular order: