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(…)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s