string
Search OperationsThe string
class provides six different search functions, each of which has four overloaded versions. Table 9.14 describes the search members and their arguments. Each of these search operations returns a string::size_type
value that is the index of where the match occurred. If there is no match, the function returns a static
member (§ 7.6, p. 300) named string::npos
. The library defines npos
as a const string::size_type
initialized with the value -1
. Because npos
is an unsigned
type, this initializer means npos
is equal to the largest possible size any string
could have (§ 2.1.2, p. 35).
The string
search functions return string::size_type
, which is an unsigned
type. As a result, it is a bad idea to use an int
, or other signed type, to hold the return from these functions (§ 2.1.2, p. 36).
The find
function does the simplest search. It looks for its argument and returns the index of the first match that is found, or npos
if there is no match:
string name("AnnaBelle");
auto pos1 = name.find("Anna"); // pos1 == 0
returns 0
, the index at which the substring "Anna"
is found in "AnnaBelle"
.
Searching (and other string
operations) are case sensitive. When we look for a value in the string
, case matters:
string lowercase("annabelle");
pos1 = lowercase.find("Anna"); // pos1 == npos
This code will set pos1
to npos
because Anna
does not match anna
.
A slightly more complicated problem requires finding a match to any character in the search string. For example, the following locates the first digit within name
:
string numbers("0123456789"), name("r2d2");
// returns 1, i.e., the index of the first digit in name
auto pos = name.find_first_of(numbers);
Instead of looking for a match, we might call find_first_not_of
to find the first position that is not in the search argument. For example, to find the first nonnumeric character of a string
, we can write
string dept("03714p3");
// returns 5, which is the index to the character 'p'
auto pos = dept.find_first_not_of(numbers);
We can pass an optional starting position to the find
operations. This optional argument indicates the position from which to start the search. By default, that position is set to zero. One common programming pattern uses this optional argument to loop through a string
finding all occurrences:
string::size_type pos = 0;
// each iteration finds the next number in name
while ((pos = name.find_first_of(numbers, pos))
!= string::npos) {
cout << "found number at index: " << pos
<< " element is " << name[pos] << endl;
++pos; // move to the next character
}
The condition in the while
resets pos
to the index of the first number encountered, starting from the current value of pos
. So long as find_first_of
returns a valid index, we print the current result and increment pos
.
Had we neglected to increment pos
, the loop would never terminate. To see why, consider what would happen if we didn’t do the increment. On the second trip through the loop we start looking at the character indexed by pos
. That character would be a number, so find_first_of
would (repeatedly) returns pos
!
The find
operations we’ve used so far execute left to right. The library provides analogous operations that search from right to left. The rfind
member searches for the last—that is, right-most—occurrence of the indicated substring:
string river("Mississippi");
auto first_pos = river.find("is"); // returns 1
auto last_pos = river.rfind("is"); // returns 4
find
returns an index of 1, indicating the start of the first "is"
, while rfind
returns an index of 4, indicating the start of the last occurrence of "is"
.
Similarly, the find_last
functions behave like the find_first
functions, except that they return the last match rather than the first:
• find_last_of
searches for the last character that matches any element of the search string
.
• find_last_not_of
searches for the last character that does not match any element of the search string
.
Each of these operations takes an optional second argument indicating the position within the string
to begin searching.