Chapter 8. Searching

WHAT'S IN THIS CHAPTER?

  • Searching and replacing text in a single file

  • Searching and replacing text across multiple files

  • Using advanced search patterns

  • Using search history to repeat searches and revisit results

  • Learning search shortcuts and tricks

A lot of development is spent just looking for things: finding all occurrences of a particular constant, looking for a message in a string, finding where a family of symbols is defined, and so on. Learning to use Xcode's find and replace features can save you a lot of tedious work.

Xcode provides five basic facilities for finding, and potentially replacing, text and code definitions in your project:

  • Single file search

  • Multi-file search

  • Definition search

  • Syntax-aware refactoring

  • Edit All in Scope

Taking the last two first, the Edit All in Scope feature was described in the "Editing Symbol Names" section of Chapter 7. Refactoring, which can change (aka find and replace) symbol names intelligently, is described in Chapter 10. All of the remaining tools are described in this chapter.

Single and multi-file search tools search the text files in your project for text patterns or regular expressions, and optionally replace them, either individually or en masse. You can also search your project's symbol definitions (Code Sense index) intelligently to locate the code that defines a symbol.

Xcode keeps a history of your searches and their results, making it easy to repeat a search or revisit the result of a former one. Finally, a lot of shortcuts and tricks exist for performing all kinds of find and replace actions swiftly and effortlessly.

SEARCHING AND REPLACING TEXT IN A SINGLE FILE

The single file search bar appears at the top of the active editor pane whenever you choose either the Edit

SEARCHING AND REPLACING TEXT IN A SINGLE FILE
FIGURE 8-1

Figure 8-1. FIGURE 8-1

The search bar has two modes: the find mode appears when you choose the Find command. The replace mode appears when you choose the Find and Replace command. You can change between modes using the pop-up menu on the left, or by choosing one of the alternate search commands. Dismiss the search bar by clicking the Done button or pressing the Esc key.

Setting Search Options

The search bar contains a search pattern field, previous and next match buttons, a search options menu, and clear button, all shown in Figure 8-2.

FIGURE 8-2

Figure 8-2. FIGURE 8-2

Type the text pattern you want to find in the search field and use the next or previous button to jump to the next (or previous) occurrence of that pattern in the file. The commands Edit

FIGURE 8-2

The search menu, also shown in Figure 8-2, has a number of options that control the search behavior and how the search pattern is interpreted, as shown in the following table.

SEARCH OPTION

EFFECT

String Matching

Search pattern is a literal string.

Regular Expression

Search pattern is a regular expression.

Ignore Case

Letters in the search pattern match both upper- and lowercase text.

Wrap Around

If there are no more occurrences of the search pattern in the file, the next and previous commands continue searching from the beginning or end of the file, respectively.

Contains

Search string matches any sequence of text in the file.

Starts With

Search string only matches text that starts at a word boundary.

Whole Words

Search string only matches text that starts and ends at word boundaries.

Ends With

Search string only matches text that ends at a word boundary.

Recent Searches

A menu of recent search patterns.

Clear Recent Searches

Clears the Recent Searches menu.

The String Matching and Regular Expression options are mutually exclusive. The word boundary options (Contains, Starts With, Whole Word, and Ends With) apply only to String Matching. Regular Expression searches can also be restricted to word boundaries, but you'll have to include that as part of the regular expression. Read more about regular expressions in the "Regular Expression Search" section later in this chapter.

Replacing Text

Switching the search bar to replace mode adds a replacement text field and three new buttons: Replace All, Replace, and Replace & Find. These buttons are equivalent to the commands Edit

Replacing Text

COMMAND

EFFECT

Replace All

Replaces all occurrences of the pattern with the contents of the replacement text field. The current text selection is ignored.

Replace

Replaces the current text selection with the replacement text field. The current selection, or insertion point, doesn't have to match the search pattern; it's unconditionally replaced.

Replace and Find Next/Previous

Perform a Replace, and then find the next (or previous) occurrence of the search pattern.

All replacements performed by Replace All occupy a single step in the file's undo history. Performing an Edit

Replacing Text

If you searched for text using a regular expression, you may want to read the section "Replacing Text Using Regular Expressions" later in this chapter.

SEARCHING AND REPLACING TEXT IN MULTIPLE FILES

Every open project has a single Project Find window. Choose the Edit

SEARCHING AND REPLACING TEXT IN MULTIPLE FILES
FIGURE 8-3

Figure 8-3. FIGURE 8-3

At the top of the window are the search and replace options. The middle pane displays a summary of search results. The bottom pane is an editor that jumps to a selected search result.

The find and replace fields, search options, and buttons are functionally equivalent to those in the editor's search bar. In addition, there are controls to select the set of files to be searched along with some special search options.

To the right of the Find and Replace fields are three pop-up menus. The top one selects the batch find options set to use, which essentially determines the set of files to search. Normally, this is set to In Project, which searches all of the source items in the project. The Options button lets you alter the batch find options and define your own sets. Batch find options are described later in the section "Batch Find Options."

The middle pop-up menu selects how the Find field is interpreted and can be set to one of:

  • Textual

  • Regular Expression

  • Definitions

  • Symbols

The first two choices, Textual and Regular Expression, are the same as the String Matching and Regular Expression search options described earlier for single file searches. In addition, you can search your project's Code Sense index for definitions or symbols. Those search types are described later in the "Symbol Search" section.

The bottom pop-up selects between the four textual search modes: Contains, Starts With, Ends With, and Whole Words. Like the single file search, word boundary options apply to all search types except Regular Expression. The Ignore Case option works the same way it does in the editor's search bar.

Finding a Pattern in Multiple Files

Once you've entered a search pattern in the Find field and selected the relevant options, the Find button searches for every instance of the search pattern in every file of the file set. There is no direction (for example, forward or backward); a project find is a single, monolithic search that produces a list of matches. The results of the search are normally displayed in the middle pane of the window, as shown in Figure 8-4. If they are not, make sure the Display Results in Find Smart Group option is not checked. This option is described later in the "Find Results Smart Group" section.

FIGURE 8-4

Figure 8-4. FIGURE 8-4

Every file that contains the search pattern is listed in the results pane as a group. The individual lines within each file that match the pattern are listed below each file. Use the disclosure triangle next to the file to collapse or expand the group, temporarily hiding all of the "hits" in a specific file. The text that matched the search pattern is displayed in bold text. A single line may appear more than once if the search patterns occurred several times in that line.

Select any line in the search results list and the matching text is immediately displayed in the editor pane at the bottom of the window. You can resize the divider between the list and the editor pane, or collapse it by double-clicking it. This is a full-featured editor pane, supporting all of the built-in editing features described in Chapter 6 — including its own single file search bar.

Warning

Recalling an earlier search pattern from the search history also recalls the search results for that pattern. See the section "Search History" for more about recalling previous search patterns.

With the search results pane active, the up and down arrow keys move from one search result to the next, allowing you to skip quickly to each found pattern, revealing its context in the editor pane.

Replacing Text in Multiple Files

The Replace button replaces some or all of the occurrences listed in the find results with the text in the Replace field. Regular Expression searches can use replacement variables (see the section "Replacing Text Using Regular Expressions" later in this chapter). The selected text lines in the results list determine which occurrences are replaced. If no source lines are selected, all listed occurrences are replaced. If one, or more, text lines is selected, only those occurrences are replaced. Note that selecting a file group in the list has no effect and is not considered an occurrence. Use the Edit

Replacing Text in Multiple Files

Clicking the Replace button presents a dialog box like the one in Figure 8-5. Make a habit of reading the confirmation dialog box before committing to the replace. It is very easy to accidentally replace all occurrences when you just wanted to replace one, or a subset of the occurrences when you wanted to replace them all. The latter usually happens when you perform a search, browse the results (leaving text lines in the results list selected), and then perform the replace — mistakenly thinking that Xcode will replace them all.

FIGURE 8-5

Figure 8-5. FIGURE 8-5

Batch Find Options

Which files the Find command in the Project Find window searches for is determined by the batch find options. Batch find options are stored in sets. You select a set using the top pop-up menu control in the Project Find window. By default, the set is In Project. This set searches all of the files referred to by the project, excluding those in frameworks. Clicking the Options button presents the Batch Find Options window, shown in Figure 8-6.

FIGURE 8-6

Figure 8-6. FIGURE 8-6

The batch find options set you are modifying is controlled by the Find Sets pop-up menu at the top of the window. Be careful: the Find Sets selection usually defaults to the set you have selected in the find window, but might not. After clicking the Options button, first make sure you are editing the correct set before changing anything.

Warning

Batch find options sets are global; changing the settings for an existing set changes its definition for all projects. The best advice is never to change any of the settings in the predefined sets — changing the "In Project" set to search frameworks really defeats the purpose of having a set named "In Project." If you want to define a special set of options, create a custom set; it's easy to do.

Create additional batch find options sets using the Add button at the top of the window. Give the new set a name and then edit its settings as you see fit. Remember that editing a set doesn't alter the set selected in the Project Find window. After you've created a new set, remember to select that set in the Project Find window in order to use it.

The Delete button deletes the current batch find options set. There is no confirmation; the set is deleted immediately and permanently for all projects.

The four check boxes at the left enable one of four sets of files; the union of those sets defines the complete set of files that will be searched — subject to some additional filtering. The possible sets are:

  • The Search in Open Documents option includes any file open in any editor pane.

  • The Search in Open Projects option includes files to which open projects refer. Which files, and from which projects, is defined by the next two radio button groups.

    • The first group determines which files are included, and can be set to Selected Files in This Project, All Files in This Project, All Open Projects, or This Project and Referenced Projects. Normally, it is set to All Files in This Project and only searches the files in the current project. If you typically work with multiple projects that are related, using All Open Projects or This Project and Referenced Projects lets you search the files in all open or related projects. Selected Files in This Project requires that you first select the specific files you want to search in the project source group.

    • The second radio button group considers whether the project source file reference is part of a framework. Project Files and Frameworks includes all source files to which the project refers, including all of the source files in any frameworks. Project Files Only excludes the headers and source files contained in frameworks. Frameworks Only searches only the headers and source files in the frameworks, ignoring the source files of the project itself.

  • The Search in Included Files option adds any files included by files to the set.

  • The Search in Files and Folders option adds the arbitrary list of files and folders immediately underneath the option to the set. Add a file or directory by clicking the plus (+) button below the list, or simply drag files and folders into the list. Remove items from the list by selecting them and clicking the minus (-) button or pressing the Delete key. Each batch find options set has its own list of additional files.

On the right are filtering options that refine the set of files to search:

  • The All Candidate Files option doesn't exclude any files; it searches all of the text files defined by the other options.

  • The Source Files Only option limits the search to candidate files that contain source code. Text files such as documentation, RTF, XML, and HTML are skipped.

  • The Filter Files Using regex Patterns option allows you to filter the candidate set of files by filename and extension using regular expressions.

When filtering using regular expressions, each enabled (checked) regular expression in the patterns list is applied to each candidate filename. If the filename matches all of the checked expressions, it's included in the search. If not, it's ignored. The key points to keep in mind when editing the regular expression pattern list are:

  • The pattern list is global. Changing a pattern's definition changes it for every batch find options set in every project.

  • A batch find options set uses only those patterns that are enabled (checked) for that set. Each set remembers which patterns it uses.

  • A candidate filename must match all of the checked patterned. In other words, the set of files to search is formed by the intersection (logical AND) of the file sets defined by each regular expression.

  • The Include/Exclude option inverts the sense of the regular expression: when set to Include, a file is a member if it matches the expression. When set to Exclude, a file is a member if it does not match the expression.

Add a pattern to the list using the + button below the list; remove patterns using the - button. Check the pattern (to enable it), and then double-click the pattern to edit it, as shown in Figure 8-7.

FIGURE 8-7

Figure 8-7. FIGURE 8-7

Warning

Each batch find options set remembers which patterns it uses, but the patterns themselves are a global list, shared by all sets of every project. This allows you to share patterns with other sets and projects easily, but also means that if you edit a pattern you're changing the rule for every batch finds options set everywhere. When in doubt, create a new pattern.

To the left of each pattern is the Include/Exclude control that determines whether the pattern must match (or not match) a filename to be included in the set.

For a file to be included in the search, its name must satisfy all of the checked regular expression patterns in the list. If the list has the two patterns Include .m$ and Include .h$ both checked, then no files will be searched; there is no filename that will match both .m$ and .h$. In general, use at most one Include pattern to define the principle group of files to consider, and then use additional Exclude terms to winnow out unwanted files.

SEARCH PATTERNS

The various Find commands all apply a search pattern to the text of your files in order to find the text that matches the pattern. Xcode gives you a lot of flexibility in specifying the parameters of your search, from a simple, unanchored literal text string to complex regular expressions. This section describes some of the finer points of the three kinds of search that Xcode performs.

Textual or String Search

Searching for a string, also referred to as a textual or literal string search, is the simplest type of search. The search scans the text of a file looking for the exact sequence of characters in the search pattern field.

You can refine the search by requiring that a pattern be found on a word boundary. The options are described in the following table.

SEARCH MODE

STRING MATCHES

Contains

Matches the string pattern anywhere in the text. This option turns off word boundary restrictions.

Starts With

Matches text starting with the character immediately after a word boundary.

Ends With

Matches text ending with the character immediately preceding a word boundary.

Whole Words

Matches text only if both the first and the last characters of the matched text begin and end on word boundaries.

The Ignore Case option causes case differences between the text and the string pattern to be ignored. With this option on, the letters a or A in the pattern will match any a or A in the text, interchangeably. Likewise, the letter ü will match either ü or Ü in the text, but not u, ù, ú, or û. Matching is based on the Unicode rules for letter case. This option has no effect on punctuation or special characters. These must always match exactly.

Regular Expression Search

For those of you who have been living in a cave since the 1960s, regular expressions are strings of characters that describe patterns of text. Using a textual match, described in the previous section, the pattern "c.t" would match the literal text "c.t" in a file. In a regular expression the period character (.) is instead interpreted as a pattern that means "match any single character." Thus, the regular expression "c.t" describes a sequence of three characters: The letter c, followed by any character, followed by the letter t. This pattern would match the words "cat," "cut," and "cot," as well as the text "c.t."

Regular expressions are an expansive topic; entire books have been written on the subject. The following primer should give you a basic introduction to the most useful regular expressions. It should also serve as a handy reference to the patterns and operators supported by Xcode.

Regular Expressions

In simplified terms, regular expressions are constructed from patterns and operators. Patterns define a character to match, and operators augment how those patterns are matched. The key concept to keep in mind is that operators do not, by themselves, match anything. A pattern matches something and an operator must have a pattern on which to operate.

Patterns

Every pattern in a regular expression matches exactly one character. Many patterns match a special character or one character from a set of possible characters. These are called meta-character patterns. The most common are listed in the following table.

PATTERN

MATCHES

.

Matches any character.

character

Quotes one of the following special characters: *, ?, +, [, (, ), {, }, ^, $, |, , ., or /.

^

Matches at the beginning of a line.

$

Matches at the end of a line.



Matches a word boundary.

B

Matches a non-word boundary.

[set]

Matches any one character from the set. Sets are explained in more detail a little later.

Any single character that is not a meta-character pattern, nor a regular expression operator, is a literal pattern that matches itself. The string cat is, technically, a regular expression consisting of three patterns: c, a, and t. This expression would match the word "cat," which is a really long-winded way of saying that anything that doesn't contain any kind of special expression will match itself just as if you had searched for a literal string.

The . pattern is used quite often with operators, but it can always be used by itself as was demonstrated in the previous "c.t" example.

Another useful pattern is the escape pattern. Most punctuation characters seem to have some special meaning in regular expressions. If you need to search for any of these characters — that is, use the character as a pattern and not an operator — precede it with a backslash. The pattern . matches a single period in the text. The pattern \ matches a single backslash character.

The four patterns ^, $, , and B are called boundary patterns. Rather than match a character, like regular patterns, they match the location between two characters. The first two match the positions at the beginning and end of a line, respectively. For example, the regular expression ^# matches a single pound-sign character only if it is the first character on the line. Similarly, the expression ;$ matches a single semicolon only if it is the last character on a line.

The  pattern matches the word boundary between characters. In Textual search mode, you used the Whole Words option to require that the first and last characters of the pattern "one" was found between two word boundaries. The equivalent regular expression is one. The B pattern is the opposite and matches the position between two characters only if it is not a word boundary. The regular expression Bone matches "done" but not "one."

The last pattern is the set. A set matches any single character contained in the set. The set [abc] will match a, b, or c in the text. The expression c[au]t will match the words "cat" and "cut," but not the word "cot." Set patterns can be quite complex. The following table lists some of the more common ways to express a set.

SET

MATCHES

[characters]

Matches any character in the set.

[^set]

Matches any character not in the set.

[a-z]

Matches any character in the range starting with the Unicode value of character a and ending with character z, inclusive.

[:named set:]

Matches any character in the named set. Named sets include Alphabetic, Digit, Hex_Digit, Letter, Lowercase, Math, Quotation_Mark, Uppercase, and White_Space. For example, the set [:Hex_Digit:] matches the same characters as the set [0123456789abcdefABCDEF]. Named sets often include many esoteric Unicode characters. The : Letter: set includes all natural language letters from all languages.

The [, ], -, and ^ characters may have special meaning in a set. Escape them ([X-]) to include them in the set as a literal character. Sets can be combined and nested. The set [[:Digit:]A-Fx] will match any character that is a decimal digit, or one of the letters A, B, C, D, E, F, or x.

A number of special escape patterns also exist, as listed in the following table. Each begins with the backslash character. The letter or sequence that follows matches a single character or is shorthand for a predefined set.

META-CHARACTER

MATCHES

Matches a single tab character.

Matches a single line feed character.

Matches a single carriage return character.

uhhhh

Matches a single character with the Unicode value 0xhhhh. u must be followed by exactly 4 hexadecimal digits.

Uhhhhhhhh

Matches a character with the Unicode value 0xhhhhhhhh. U must be followed by exactly 8 hexadecimal digits.

d, D

Matches any digit (d) or any character that is not a digit (D). Equivalent to the sets [:Digit:] and [^:Digit:].

s, S

Matches a single white space character (s), or any character that is not white space (S).

w, W

Matches any word (w) or non-word (W) character.

Operators

Although patterns are very flexible in matching specific characters, the power of regular expressions is in its operators. Almost every operator acts on the pattern that precedes it. The classic regular expression .* consists of a pattern (.) and an operator (*). The pattern matches any single character. The operator matches any number of instances of the preceding pattern. The result is an expression that will match any sequence of characters, including nothing at all. The following table summarizes the most useful operators.

OPERATOR

DESCRIPTION

*

Matches the pattern 0 or more times.

+

Matches the pattern 1 or more times.

?

Matches the pattern 0 or 1 times.

|

Matches the pattern on the left or the right of the operator. A|B matches either A or B.

{n}

Matches the pattern exactly n times, where n is a decimal number.

{n,}

Matches that pattern n or more times.

{n,m}

Matches the pattern between n and m times, inclusive.

*?, +?, ??, {n,}?, {n,m}?

Appending a ? causes these operators to match as few a number of patterns as possible. Normally, operators match as many copies of the pattern as they can.

(regular expression)

Capturing parentheses. Used to group regular expressions. The entire expression within the parentheses can be treated as a single pattern. After the match, the range of text that matched the parenthesized subexpression is available as a variable that can be used in a replacement expression.

(?flags-flags)

Sets or clears one or more flags. Flags are single characters. Flags that appear before the hyphen are set. Flags after the hyphen are cleared. If only setting flags, the hyphen is optional. The changes affect the remainder of the regular expression.

(?flags-flags: regular expression)

Same as the flags-setting operator, but the modified flags only apply to the regular expression between the colon and the end of the operator.

The four repetition operators (*, +, ?, and {n,m}) search for some number of copies of the previous pattern. The only difference between them is the minimum and maximum number of times a pattern is matched. As an example, the expression [0–9]+ matches one or more digits and would match the text "150" and "2," but not "one" (it contains no digits).

The ? modifier makes its operator parsimonious. Normally operators are "greedy" and match as many repetitions of a pattern as possible. The ? modifier causes repetition operators to match the fewest occurrences of a pattern that will still satisfy the expression. As an example, take the line "one, two, three, four." The expression .*, matches the text "one, two, three," because the .* can match the first 15 repetitions of the . pattern and still satisfy the expression. In contrast, the pattern .*?, matches only the text "one," because it only requires three occurrences of the . pattern to satisfy the expression.

Use parentheses both to group expressions and to capture the text matched by a subexpression. Any expression can be treated as a pattern. The expression M(iss)+ippi matches the text "Mississippi." It would also match "Missippi" and "Missississippi." You can create very complex regular expressions by nesting expressions. The expression (0x[:Hex_Digit:]+(,s*)?)+ matches the line "0x100, 0x0, 0x1a84e3, 0xcafebabe." Dissecting this expression:

  • 0x[:Hex_Digit:]+ matches a hex constant that begins with 0x followed by one or more hex digits.

  • The (,s*)? subexpression matches a comma followed by any number of white space characters, or nothing at all (the ? operator makes the entire expression optional).

  • Finally, the whole expression is wrapped in parentheses such that the + operator now looks for one or more repetitions of that entire pattern.

Finally, you can use the flag operators to alter one of the modes of operation. Flags before the hyphen turn the flags on; flags after the hyphen turn the flags off. If you're only turning one or more flags on, the hyphen can be omitted. The first version of the operator sets the flag for the remainder of the expression. The second version sets the flag only for expression contained within the operator. The only really useful flag is case-insensitive mode:

FLAG

MODE

i

Case-insensitive mode. If this flag is set, the case of letters is not considered when matching text.

You can set or clear the i flag anywhere within an expression. When you set this flag, expressions match text irrespective of case differences. The case sensitivity at the beginning of the expression is determined by the setting of the Ignore Case option in the Find window. The expression one (?i)TWO (?-i)three will match the text "one two three," but not "ONE TWO THREE."

Finally, whatever regular expression you use, it cannot match "nothing." Double negative aside, the expression cannot match an empty string; if it did, it would theoretically match every position in the entire file. The solitary expression .* will match any number of characters, but it will also match none at all, making it an illegal pattern to search for. If you try to use such a pattern, Xcode warns you with a dialog saying "Regular expression for searches must not match the empty string."

Try Some Regular Expressions

If you're new to regular expressions, I recommend that you try a few out to become comfortable with the concepts. Start with the source file shown in Listing 8-1.

Example 8-1. Example file text

#define ONE    1
#define TWO    2
#if ONE+TWO != 3
    #warning "Math in this universe is not linear."
#endif

/////////////////
// Static data //
/////////////////

static Number series[] = {
        { 1, "one",     0x1 },
        { 2, "two",     0x0002 },
        { 3, "three",   0x0003 },
        { 4, "four",    0x0004 },
        { 5, "five",    0x0005 },
        { 6, "six",     0x0006 },
        { 7, "thirteen",0x000d }
    };

/////////////
// Methods //
/////////////

/*!
 *    @abstract Establish the logical Set used by the receiver
 *    @param set The set to use. Will be retained by receiver. Can be null.
 */

- (void)setSet:(Set*)set
{
    [workingSet autorelease];    /* release any old set we might still be using */
    workingSet = [set retain];    /* retain this set */
}

/*!
 *    @abstract Get the set being used by this object.
 *    @result The logical set used by this object. If none, an empty set is returned.
 */

- (Set*)getSet
{
    if (set!=null)
        return set;
    return [[[Set alloc] init] autorelease];
}

Open the file and choose Edit

Example file text
  • one

  • one

  • Set

  • BSet

  • [.*]

  • [.*]

  • /+

  • /{2}.*

  • /*.**/

  • ^#w+

  • ".*"

  • ".{3,5}"

  • ".{1,10}", +0x[0-9a-f]{4}

  • ".{1,10}",s*0x[0-9a-f]{1,4}

  • ONE|TWO

  • (?i:ONE)|TWO

Searching for one found "one" and "none" but not "ONE." There were no special regular expression patterns or operators, making the search equivalent to a simple textual search. The expression one required that the c and e start and end on word boundaries, making it equivalent to a textual search in Whole Word mode.

Using variations of the word boundary pattern, Set searched for text where the S starts a word, and is equivalent to a textual search in Begins With mode. BSet specifies just the opposite and has no textual search equivalent. It only found the text "Set" when the S did not begin a word.

The expression [.*] matched any single period or asterisk in the file. Operators lose their meaning within a set and become just another character. In contrast, [.*] searched for an open bracket, followed by any sequence of characters, followed by a close bracket. By escaping [ and ] they are no longer treated as defining a set and instead are simple literal patterns that match a single bracket character. Now that they are not in a set, the . and * characters assume their more common meanings as a pattern and operator.

/+ matched one or more slash characters. Most would be C++-style comments, but it would also match a single /. The expression to match a C++-style comment is /{2}.*. This matches two consecutive slash characters followed by anything else up to the end of the line.

/*.**/ matched the more traditional C-style comments in the file. Note that the two literal *'s had to be escaped to avoid having them treated as operators.

^#w+ matched a pound sign following by a word, but only if it appears at the beginning of the line. The pattern found "#define", "#if", and "#endif", but not "#warning".

".*" matched anything between double quotes. In the pattern ".{3,5}" this was limited to anything between double quotes that was between three and five characters long.

".{1,10}", +0x[0-9a-f]{4} is a complex expression designed to match statements in the Number table. If you opened the text file in the example projects, you'll notice that it failed to match the lines containing "one," "four," and "thirteen." It misses "one" because the 0x[0-9a-f]{4} expression requires exactly 4 hexadecimal digits following the "0x" and that line only has 1 digit. The line with "four" is missed because the white space between the comma and the "0x" turns out to be spaces, not tabs. The line with "thirteen" is missed because there are no tabs at all between the comma and the hex number. The pattern ".{1,10}",s*0x[0-9a-f]{1,4} corrects all of these shortcomings. If you're typing in the text for this example by hand, use the Tab key and temporarily turn on the Tab Key Inserts Tab, Not Spaces option found in the Indentation pane of the Xcode preferences.

The expression ONE|TWO found either the text "ONE" or "TWO," but not both. The (?i:ONE)|TWO expression demonstrates altering the case-sensitivity of a subexpression. It matched "ONE," "one," and "TWO" but not "two."

Learning More about Regular Expressions

Xcode uses the ICU (International Components for Unicode) Regular Expression package to perform its regular expression searches. This chapter explained many of its more common, and a few uncommon, features. There is quite a bit more; although much of it is rather obscure. Should you need to stretch the limits of regular expressions in Xcode, visit the ICU Regular Expressions users guide at http://icu.sourceforge.net/ for a complete description of the syntax.

Replacing Text Using Regular Expressions

When searching using regular expressions, it is possible for the replacement text to contain portions of the text that was found. The parentheses operators not only group subexpressions, but they also capture the text that was matched by that subexpression in a variable. These variables can be used in the replacement text.

The variables are numbered. Variable 1 is the text matched by the first parenthetical subexpression, variable 2 contains the text matched by the second, and so on. The replacement text can refer to the contents of these variables using the syntax n, where n is the number of the subexpression. The variables in the replacement text can be used in any order, more than once, or not at all.

For example, take the text "one plus two equals three." The regular expression (w+) plus (w+) equals (w+) matches that text. Because of the parentheses, the text matched by each w+ subexpression can be used in the replacement. The replacement text 1+2=3 replaces the original text with "one+two=three" as shown in Figure 8-8.

FIGURE 8-8

Figure 8-8. FIGURE 8-8

Regular expression replacement patterns are extremely useful for rearranging repetitive statements. Use the following code snippet as an example:

static Number series[] = {
        { 1, "one",         0x1 },
        { 2, "two",         0x0002 },
        { 3, "three",       0x0003 },
        { 4, "four",        0x0004 },
        { 5, "five",        0x0005 },
        { 6, "six",         0x0006 },
        { 7, "thirteen", 0x000d }
    };

Using the regular expression mode, find the pattern:

{ ([0-9]+), (".*?")

and replace it with:

{ 2, 1

The text of subexpressions ([0-9]+) and (".*") were captured and used in the replacement text to reverse their order in the table. This replaced { 1, "one", 0x1 }, with { "one", 1, 0x1},. Note that the replacement text had to include everything outside of the subexpressions.

Here are some details to consider when using regular expression replacement variables:

  • There are only nine variables (1 through 9). If the regular expression contains more than nine parenthetical subexpressions, those expressions are not accessible. Variables that do not correspond to a subexpression are always empty.

  • If parentheses are nested, they are assigned to variables in the order that the opening parentheses appeared in the expression.

  • If a subexpression is used to match multiple occurrences of text, only the last match is retained in the variable. Using the text "one, two, three;" the regular expression ((, *)?(w+))+ matches the three words before the semicolon. A replacement pattern of 1='1' 2='2' 3='3' results in the text "1=', three' 2=', ' 3='three'" because:

    • Variable 1 contains the last occurrence of the outermost subexpression.

    • Variables 2 and 3 each contain the last occurrence of the nested subexpressions.

    • The values of the first two occurrences are lost.

Symbol Search

The Project Find window includes two special search modes: Definition and Symbol. Instead of searching the text of your project's files, these modes search the symbol names in the project's Code Sense index. These syntax-aware search modes locate symbol names that appear in the compiled portion of your source code. Their principle advantage is that they won't match other superfluous occurrences of a symbol's name, specifically those in comments.

Both symbol search modes use literal string search mode, the word boundary option, and the ignore case option, to find the symbols in the Code Sense database.

Note

For the definition and symbol search modes to be accurate, the Code Sense index must be up-to-date. That usually requires that all of your source files be first saved to disk. Some Code Sense information, particularly class and method definitions, is not updated until the files are saved. Get into the habit of performing a File

Symbol Search

Definitions Search

A definitions search finds all of the symbol definitions matching the string search pattern. A definition is where a class, method, function, or variable is defined or implemented, as shown in Figure 8-9. It will not find references to a symbol.

FIGURE 8-9

Figure 8-9. FIGURE 8-9

When performing a definitions search, the results list shows the type of the symbol and the symbol name found, rather than the line of text in the file.

The search is limited to those files in the batch find options set.

Symbol Search

A symbol search finds all of the compiled occurrences of a symbol in your project. The scope of this search mode is not defined by the batch find options set; it searches the compiled instances of symbols in your project. This does not include anything in your linked frameworks, because linked frameworks are not a compiled by your project.

Figure 8-10 illustrates one of the big advantages of using the symbol search mode. The figure shows finding all compiled references to the willUpdateCalculator:field: method. Three are shown here: a reference to its selector constant, a method invocation, and the method's definition. Notice that the occurrence of the text "willUpdateCalculator:field:" in the comment is not part of the search results.

FIGURE 8-10

Figure 8-10. FIGURE 8-10

Here are a few things to keep in mind when searching symbols:

  • A symbol search matches the entire expression that contains the symbol. Often this is just the symbol name (in the case of a variable of function). But in the example in Figure 8-10, the text matched is delegate willUpdateCalculator:self field:field, which is clearly more than just the symbol name.

  • Symbol names are the complete, fully qualified, symbol in the program. If you perform a symbol search using the Whole Words option, searching for "openFile" will not find the method openFile:, and "willUpdateCalculator:" will not find the method willUpdateCalculator:file:. Use the Starts With or Contains option instead.

  • The definition and symbol search modes only find literal references to symbols in your source code. For example, if the preprocessor macro CHECKPOINT expanded to code that referred to the variable testCount, a symbol search for testCount would not match a line containing the CHECKPOINT macro, even though (technically) a testCount variable reference occurs at that point in the code.

SEARCH HISTORY

As you find and replace text in your project, Xcode keeps a short history of the following:

  • Recently used search patterns

  • Recently used replacement patterns

  • The results of searches performed in the Project Find window

Retrieving search history makes it easy to repeat a search or replacement that you've previously done, perform a new search that's a minor variation of a previous search, and review search results even after the text that generated those results has changed.

Recent Search Patterns and Replacement Text

Both the single file search bar and the Project Find window keep a history of the recently used search patterns and the replacement text that was associated with it. Figure 8-2 showed the Recent Searches menu in the single file search bar. Figure 8-11 shows the recent search pattern menu in the Project Find window.

FIGURE 8-11

Figure 8-11. FIGURE 8-11

In the single file search bar, previously used search and replacement patterns are paired; choosing a previously used search pattern also recalls the replacement text it was associated with. The search pattern and replacement text fields in the Project Find window are independent of each other. You can independently recall a previously used search pattern or a previous replacement text.

New search and replace patterns are added to the top of each list, but are never duplicated in the list. Reusing a search pattern does not move it back to the top of the list.

Xcode remembers the mode used by a search pattern (Textual, Regular Expression, Definitions, or Symbol), but none of its options (word boundaries, ignore case, wrapping). If you recall a regular expression, the mode will automatically switch to Regular Expression, but if you check the Ignore Case option and then recall a previous search pattern that option will still be set.

Recent Search Results

The Project Find window also remembers the last set of search results for each pattern. Recalling a previous pattern also recalls its last result set. Previous result sets are also preserved in the Find Results Smart Group, described in the next section.

Be careful about recalling old searches or editing files between the time you did the find and the replace. The history of search results is a set of original locations. Like the single file Replace command, the Replace button inserts the replacement text at those locations even if the text no longer matches the search pattern.

The safest practice is to get into the habit of rerunning the Find again after recalling any earlier search results or after editing any files.

On the other hand, this particular "feature" can save the day. If you make a mistake in the replacement text, you can perform another replacement to correct it even if a new find won't find those occurrences anymore.

Global Search Patterns

The current search pattern is shared globally with all projects and with the Mac OS X operating system. Entering a search pattern makes it the search for every search bar and Project Find window in Xcode. In addition, the Mac OS X operating system has a global search term variable shared by all applications. Applications that use this variable will set, or honor, the search pattern in Xcode. For example, search for something in BBEdit, then switch back to Xcode. Whatever you searched for in BBEdit will be the current search pattern in Xcode, and vice versa.

The search pattern, replacement text, and search results history is local to each project and persists only as long as the project is open.

FIND RESULTS SMART GROUP

Every find executed in the Project Find window adds its results to the Find Results smart group in the project window, as shown in Figure 8-12.

FIGURE 8-12

Figure 8-12. FIGURE 8-12

Select an item in the Find Results smart group and the details pane lists the location (filename and line number) and the line or symbol definition that was found. Selecting a "hit" from the list displays that location in the project window's editor pane. You can also double-click the item or use the View

FIGURE 8-12

Unlike the recent search results in the Project Find window, the Find Results smart group remembers the results of every search performed — not just the last one for each search pattern.

If you check the Display Results in Find Smart Group option of the Project Find window, the Find Results smart group becomes your primary means of browsing the results of a search. With this option checked, the results list in the Project Find window disappears. When a find is executed, the project window becomes active and the results of the search are automatically selected. This option really only makes sense when using the All-In-One style. Leave this option unchecked to stay in the Project Find window and review the search results there.

SEARCH SHORTCUTS

Searching and replacing text during development is very common, and often repetitive. Xcode provides a number of shortcuts to keep your keystrokes and mouse clicks to a minimum. The following table lists some handy shortcuts — either keyboard shortcuts or combination commands that perform a sequence of common actions. Most apply to the text selected in the active editor pane, but those that aren't will also function in the Project Find window. Many of these same commands appear in the contextual pop-up menu in the editor pane.

ACTION

SHORTCUT

Make the selected text the search pattern

Edit

TIP TO REMEMBER

Make the selected text the replacement text

Edit

TIP TO REMEMBER

Make the selected text the search pattern and immediately find the next occurrence in the file

Edit

TIP TO REMEMBER

Make the selected text the search pattern and immediately find all occurrences using the Project Find window

Edit

TIP TO REMEMBER

Search for the selected text in the project using a literal string search

Right-click

TIP TO REMEMBER

Search for the selected text in the project's definitions

Right-click

TIP TO REMEMBER

Search for the selected text in the project's symbols

Right-click

TIP TO REMEMBER

Find the next occurrence of the pattern in the file

Edit

TIP TO REMEMBER

Find the previous occurrence of the pattern in the file

Edit

TIP TO REMEMBER

Another useful combination command is the Edit

TIP TO REMEMBER

SEARCHING LISTS

A third kind of search tool is located in the toolbar, as shown in Figure 8-13. This quick search field quickly winnows any details list to only those items that match the term in the search field.

FIGURE 8-13

Figure 8-13. FIGURE 8-13

The list could be a list of files in the project, a list of bookmarks, the project symbols, or even the results of a project search. In short, whatever you have listed in the details pane can be filtered using this search field.

In most contexts, the search field operates in one of three modes — String Matching, Wildcard Pattern, or Regular Expression — as described in the following table. Select the mode by clicking the magnifying glass at the left end of the field. The current mode is displayed in grey when the field is empty, so you know what mode it is in before you enter anything.

SEARCH MODE

DESCRIPTION

String Matching

Performs a simple textual search.

Wildcard Pattern

Wildcard patterns use the so-called "globbing" characters used by the shell. The characters * and ? will match any string or a single character, respectively. A set of characters can be defined with the set syntax: [chars]. For example, the pattern *.h will match all of the header files in a file list. Don't confuse wildcards with regular expression operators.

Regular Expression

The same regular expressions described earlier in this chapter.

In some contexts, the search field may have special modes specific to the type of list being displayed. The Project Symbols smart group displays the list of indexed symbols in the details list. When you're displaying the symbols list, the search modes change to Search All, Search Symbols, Search Kind, and Search Location. Choosing a setting other than Search All limits the search to a particular column in the table.

To use the search field, simply type something into it. Whatever you enter is immediately used to reduce the details list to only those items that match the search term. Figure 8-14 shows the effect of entering a variable name while the details list displays contents of the Project Symbols smart group. The options in the search menu also changed. When searching the symbols smart group, you can search by name, type, or file location. Because the mode was set to Search All, the search pattern "check" found the symbols checkSpelling: and checksum, but also found every symbol in the RollingChecksum.m file.

FIGURE 8-14

Figure 8-14. FIGURE 8-14

Clearing the contents of the search field, or clicking the X button at the right end of the field, cancels the search and restores the details list to its voluminous, uncensored, state.

Note

The quick search field is particularly handy when digging through the results of a search; the results of a search can be further narrowed without the need to compose a more complex search. Execute a broad search in the Project Find window, switch to the Find Results smart group, and then enter a second search term in the search field. Only those lines that match both terms are listed.

SUMMARY

You should now have at least a basic understanding of the file and project search tools. Regular expressions are a powerful tool, but using them is often more art than science. If you are new to using regular expressions, be patient. After you grasp the fundamentals of regular expressions, you will be in possession of a very powerful development tool. Don't forget the quick search field; it comes in very handy when you're wading through large projects.

The next chapter looks at progressively more sophisticated ways of renaming and restructuring your code using the Refactoring tool.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset