Search and Replace in Xcode with Regular Expressions

Recently I ran into a problem where I wanted to search for a pattern in the Xcode project and replace the found string with another one. In the past, I had had a hard time dealing with Regular expressions. This time I decided I was going to learn more about them and if possible write a post about how to use them. So here we go. How to Search and Replace in Xcode project with Regular Expressions

Enabling search and replace with regular expressions option in Xcode

To find a keyword with RegEx, go to project navigator in the left side pane. Select Find and then select Regular Expression option. This will enable finding with given regular expression statement

enable_regex_search
Replacing with regular expression

To replace a keyword with RegEx, go to the same project navigator in the left side pane. Select Replace and then select Regular Expression option. This will enable replacing with the given statement with regular expression format

enable_regex_replace

Searching for an expression in the Xcode project

Say I want to search methods in the project which take NSString as an input and return nothing. For example,

- (void)foo:(NSString*)foo

I can simply do


- \(void\)(.*):\(NSString\*\)(.*) \{

What this expression does is, it tells the search operator not to worry about method name and named parameter associated with methods matching given regular expression. All we are searching for is the method that takes NSString as an input parameter and returns nothing.

The values found using the input RegEx can be extracted using variable $1 and $2 in the example above. As you may have noted, RegEx won't work with special characters such as open and close brackets. You will have to escape them manually using backslash characters to enable searching.

In case you run into problem with RegEx containing special characters, make sure you escape them before performing any more debug steps.

To give you another example, say I want to find all return statements returning array count, I can use either of the following statements. (Depending on your coding guidelines)

return \[(.*) count\]$ or return (.*).count$.

Where the name of the array in question is stored in the special variable $1.

Please note that we're also specifying $ as an end of string characters, otherwise we will find those string too which contain count as a substring and not as an end keyword

Replacing an expression in the Xcode project

Now since we are past the initial formalities, let's dive into a slightly more complex RegEx operation of replacing an expression. Let's continue from a couple of previous examples.

As we saw,  - \(void\)(.*):\(NSString\*\)(.*) \{ can be used to search all methods taking NSString as an input parameter and returning nothing. Let's say we want to replace them with another parameter, say bar. So all methods like

- (void)foo:(NSString*)foo will now look like,

- (void)foo:(NSString*)foo andBar:(NSString*)bar.

How do we do it?

the solution is simple. You get all expressions matching with the given RegEx into pre-determined variables such as $1, $2 and so on. So all you have to do it, just put them into a replacement string and append any extra expression you want. Using the same principle, we can perform replacement with the following string.


First off, search for this,

- \(void\)(.*):\(NSString\*\)(.*) \{

And then replace it with,

- \(void\)$1:\(NSString\*\)$2 andBar:(NSInteger)bar \{

Here, the original method signature remains unchanged and that's why we chose to re-use them in the form of $1 and $2. and final result throughout your project is,

- (void)foo:(NSString*)foo andBar:(NSInteger)bar {

On a similar note, if you have changed your internal guidelines, and decided to follow another syntax to get NSArray count. ([array count] to array.count), this can be done by the following RegEx.

Simply replace

\[(.*) count\]$

with

$1.count

It will replace all message sendings with parameter access for NSArray with dot syntax

Update:

We recently ran a SwiftLint on our codebase and caught a few warnings related to legacy functions.

For example, the lint tool asked me to replace older CGRectMake with CGRect and so on. Below is how I did to find and replace other legacy expressions

  • CGRectMake

// Searching all legacy `CGRectMake` structs
// Search with following RegEx
CGRectMake\([ ]{0,1}(.*),[ ]{0,1}(.*),[ ]{0,1}(.*),[ ]{0,1}(.*)\)
// [ ]{0,1} says value followed by zero or more spaces. 
// We use this because of uncertain number of spaces before comma. 
// (.*) captures values in the form of $1, $2, etc.

// Replacing all legacy `CGRectMake` structs with new syntax

// Replace the found RegEx with following expression
CGRect\(x: $1, y: $2, width: $3, height: $4\)
// Where $1, $2 represent the values caught by previous expression matching values in the form (.*) around commas.

  • CGSize

// RegEx to search for
CGSizeMake\([ ]{0,1}(.*),[ ]{0,1}(.*)\)

// RegEx to replace with 
CGSize\(width: $1, height: $2\)

  • NSMakeRange

// RegEx to search for
NSMakeRange\([ ]{0,1}(.*),[ ]{0,1}(.*)\)

// RegEx to replace with 
NSRange\(location: $1, length: $2\)

Here are some more examples of search and replace operations using regular expressions in Xcode,

A. Adding a new parameter to the method

   Example method call: myPrint(number: 100)

   RegEx for search: myPrint\( (.*)\)$

   RegEx for replace: myPrint\($1, number: 2\)

B. Removing parameter from method

   Example method call: myPrint(number: 100, number2: 200)

   RegEx for search: myPrint\( (.*), (.*)\)

   RegEx for replace: myPrint\($1\)

These are all the examples I could find to demonstrate search and replace operation using regular expressions. If you have specific problem use-cases which can be solved using regular expressions in Xcode, please let me know. I will be happy to amend the existing list of examples with new ones

Hope this helps if you are dealing with relatively large codebase. Simple expressions are easy to search and replace, but if you can use RegEx to search and replace complex expressions, why not? Still better than manual search and replace which is more prone to human errors

Thanks to This post by Road fire software which was a great resource and inspiration for this post