Using Regular Expressions to replace text in Xcode

Surely you already know how to use Xcode’s Find and Replace feature to fix deprecated APIs in your project like the UITextAlignment to NSTextAlignment change. But did you also know you can replace regular expressions in Xcode? First, let’s look at replacing text…

Replacing Text in Xcode

So as you probably know, you can replace text in your project with the Find Navigator (which is in the left pane – the search icon). So if you’re ready to get rid of all those deprecated UITextAlignments in your code and replace them with the newer, better NSTextAlignment, you can do this:

Replace Text in Xcode

So in the pane, just select Replace > Text > Containing and in the Find bar, enter:

UITextAlignment

and in Replace:

NSTextAlignment

and then click Replace All, and you’re done.

But do you know how to replace code like this…

[self presentModalViewController:nav animated:YES];

with the now-recommended API?

[self presentViewController:nav animated:YES completion:nil];

OK, well, that’s easy enough if you’re always presenting a modal called ‘nav’. Just do this…

Replace Text in Xcode, again

Find:

presentModalViewController:nav animated:YES

Replace:

presentViewController:nav animated:YES completion:nil

and Replace All again, and you’re done. Right? Er, maybe not…

What if you also present a modal called ‘vc’ somewhere else in your code?

[self presentModalViewController:vc animated:YES];

As you can see, you’d have to do your Find and Replace again with the ‘vc’ this time. But that’s a waste of time, especially if you also present modals with different names, like ‘controller’ and ‘myVC’ and ‘someViewController’. And what if you pass in ‘NO’ for animated:? How many Find and Replaces are you going to need to do? Five? Ten? A couple dozen?

Regular expressions to the rescue! A single Find/Replace can fix all of these deprecated API calls…

Replacing Regular Expressions in Xcode

Replace with Regular Expression in Xcode

Find:

presentModalViewController:(.*) animated:(.*)\]

Replace:

presentViewController:$1 animated:$2 completion:nil]

(Make sure you select Replace > Regular Expression in the Find Navigator for this one.)

If you’re not familiar with regular expressions, you may be wondering “What in the world are those parens around the anything matcher (.*)? And what is that $1 and $2?” The parentheses create groups, and you can reference the groups by index. Note that the the indexes start at 1 in regular expressions (or regexes), as opposed to indexes that start at 0 in NSArrays, for example.

Let’s break down the Find expression. First, match all these characters:

presentModalViewController:

Then, match any characters, and group it so we can reference it later. In this case, we’re telling it to match the ‘nav’ or ‘vc’ or whatever happens to come after presentModalViewController: and hang on to it so we can use it later (in the ‘Replace’).

(.*)

The parentheses indicate that this is a group we want to reference later. And since this is the first group, we’ll be able to reference it later with $1.

Next, match the following exact characters:

 animated:

Then match another group of anything – in this case, since it follows the animated:, in practice it probably won’t be just anything – it’ll be either ‘YES’ or ‘NO’. But we don’t really care, so we’re matching anything:

(.*)

Again, parentheses indicate we’ll want to reference this group of matched characters later (again, in the Replace). And we’ll be able to reference this group later as $2 since it’s the second group in our regex.

And finally, match the closing square bracket:

\]

We need to match on the closing square bracket so our “match anything” knows where to stop. This is so we don’t end up replacing the entire line, but only everything up to the ‘]’ in our code. And the slash (‘\’) escape character here is necessary since square brackets normally have special meaning in a regex.

And now on to the replace regex. Let’s start replacing the matched string with the following exact characters:

presentViewController:

Moving on, take the first group we matched (the first “(.*)”, which should be the name of the presented view controller) and use it in the replacement string:

$1

Then use the following exact characters in the replacement string:

 animated:

And take the second group we matched (the second “(.*)”, likely a ‘YES’ or ‘NO’) and use it in the replacement string:

$2

And finally, use the following exact characters in the replacement string:

 completion:nil]

And that’s it. Hit the Replace All button, and BAM! your project is free of deprecated presentModalViewController:animated: API calls, all in a single Find and Replace.

Related Posts

Developing for iOS 7 (and supporting iOS 6)