Team LiB
Previous Section Next Section

9.6. strings Revisited

9.6. 再谈 string 类型

We introduced the string type in Section 3.2 (p. 80). Table 9.12 (p. 337) recaps the string operations covered in that section.

第 3.2 节介绍了 string 类型,表 9.12 扼要重述了在该节中介绍的 string 操作。

Table 9.12. string Operations Introduced in Section 3.2
表 9.12 第 3.2 节介绍的 string 操作

string s;

Defines a new, empty string named s.

定义一个新的空 string 对象,命名为 s

string s(cp);

Defines a new string initialized from the null-terminated C-style string pointed to by cp.

定义一个新的 string 对象,用 cp 所指向的(以空字符 null 结束的)C 风格字符串初始化该对象

string s(s2);

Defines a new string initialized as a copy of s2.

定义一个新的 string 对象,并将它初始化为 s2 的副本

is >> s;

Reads a whitespace-separated string from the input stream is into s.

从输入流 is 中读取一个以空白字符分隔的字符串,写入 s

os << s;

Writes s to the output stream os.

将 s 写到输出流 os 中

getline(is, s)

Reads characters up to the first newline from input stream is into s.

从输入流 is 中读取一行字符,写入 s

s1 + s2

Concatenates s1 and s2, yielding a new string.

把 s1 和 s2 串接起来,产生一个新的 string 对象

s1 += s2

Appends s2 to s1.

将 s2 拼接在 s1 后面

Relational Operators

关系操作符

The equality (== and !=) and relational (<, <=, >, and >=) can be used to compare strings. string comparison is equivalent to (case-sensitive) dictionary ordering.

相等运算(== 和 !=)以及关系运算(<<=>>=)都可用于 string 对象的比较,等效于(区分大小写的)字典次序的比较


In addition to the operations we've already used, strings also supports most of the sequential container operations. In some ways, we can think of a string as a container of characters. With some exceptions, strings support the same operations that vectors support: The exceptions are that string does not support the operations to use the container like a stack: We cannot use the front, back, and pop_back operations on strings.

除了已经使用过的操作外,string 类型还支持大多数顺序容器操作。在某些方面,可将 string 类型视为字符容器。除了一些特殊操作,string 类型提供与 vector 容器相同的操作。string 类型与 vector 容器不同的是,它不支持以栈方式操纵容器:在 string 类型中不能使用 front、back 和 pop_back 操作。

The container operations that string supports are:

string 支持的容器操作有:

  • The typedefs, including the iterator types, listed in Table 9.5 (p. 316).

    表 9.5 列出的 typedef,包括迭代器类型。

  • The constructors listed in Table 9.2 (p. 307) except for the constructor that takes a single size parameter.

    表 9.2 列出的容器构造函数,但是不包括只需要一个长度参数的构造函数。

  • The operations to add elements listed in Table 9.7 (p. 319) that vector supports. Note: Neither vector nor string supports push_front.

    表 9.7 列出的 vector 容器所提供的添加元素的操作。注意:无论 vector 容器还是 string 类型都不支持 push_front 操作。

  • The size operations in Table 9.8 (p. 324).

    表 9.8 列出的长度操作。

  • The subscript and at operations listed in Table 9.9 (p. 325); string does not provide back or front operations listed in that table.

    表 9.9 列出的下标和 at 操作;但 string 类型不提供该表列出的 back 和 front 操作。

  • The begin and end operations of Table 9.6 (p. 317).

    表 9.6 列出的 begin 和 end 操作。

  • The erase and clear operations of Table 9.10 (p. 326); string does not support either pop_back or pop_front.

    表 9.10 列出的 erase 和 clear 操作;但是 string 类型不入提供 pop_back 或 pop_front 操作。

  • The assignment operations in Table 9.11 (p. 329).

    表 9.11 列出的赋值操作。

  • Like the elements in a vector, the characters of a string are stored contiguously. Therefore, string supports the capacity and reserve operations described in Section 9.4 (p. 330).

    与 vector 容器的元素一样,string 的字符也是连续存储的。因此,string 类型支持第 9.4 节描述的 capacity 和 reserve 操作。

When we say that string supports the container operations, we mean that we could take a program that manipulates a vector and rewrite that same program to operate on strings. For example, we could use iterators to print the characters of a string a line at a time to the standard output:

string 类型提供容器操作意味着可将操纵 vector 对象的程序改写为操纵 string 对象。例如,以下程序使用迭代器将一个 string 对象的字符以每次一行的方式输出到标准输出设备:

     string s("Hiya!");
     string::iterator iter = s.begin();
     while (iter != s.end())
         cout << *iter++ << endl; // postfix increment: print old value

Not surprisingly, this code looks almost identical to the code from page 163 that printed the elements of a vector<int>.

不要奇怪,这段代码看上去几乎与第 5.5 节中输出 vector 容器元素的程序一模一样。

In addition to the operations that string shares with the containers, string supports other operations that are specific to strings. We will review these string-specific operations in the remainder of this section. These operations include additional versions of container-related operations as well as other, completely new functions. The additional functions that string provides are covered starting on page 341.

除了共享容器的操作外,string 类型还支持其他本类型特有的操作。在本节剩下的篇幅吕,我们将回顾这些 string 类型特有的操作,包括与其他容器相关操作的补充版本,以及全新的函数。string 类型的补充函数将在第 9.6.2 节介绍。

The additional versions of the container operations that string provides are defined to support attributes that are unique to strings and not shared by the containers. For example, several operations permit us to specify arguments that are pointers to character arrays. These operations support the close interaction between library strings and character arrays, whether null-terminated or not. Other versions let us use indices rather than iterators. These versions operate positionally: We specify a starting position, and in some cases a count, to specify the element or range of elements which we want to manipulate.

string 类型为某些容器操作提供补充版本,以支持 string 特有的、不为其他容器共享的属性。例如,好几种操作允许指定指向字符数组的指针参数。无论字符串是否以空字符结束,这些操作都支持标准库 string 对象与字符数组之间的紧密交互作用。其他版本则使用程序员只能使用下标而不能使用迭代器。这些版本只能通过位置操纵元素:指定起始位置,在某些情况下还需指定一个计数器,由此指定要操纵的某个元素或一段元素。

Exercises Section 9.6

Exercise 9.34:

Use iterators to change the characters in a string to uppercase.

使用迭代器将 string 对象中的字符都改为大写字母。

Exercise 9.35:

Use iterators to find and to erase each capital letter from a string.

使用迭代器寻找和删除 string 对象中所有的大写字符。

Exercise 9.36:

Write a program that initializes a string from a vector<char>.

编写程序用 vector<char> 容器初始化 string 对象。

Exercise 9.37:

Given that you want to read a character at a time into a string, and you know that the data you need to read is at least 100 characters long, how might you improve the performance of your program?

假设希望一次读取一个字符并写入 string 对象,而且已知需要读入至少 100 个字符,考虑应该如何提高程序的性能?


The string library defines a great number of functions, which use repeated patterns. Given the number of functions supported, this section can be mind-numbing on first reading.

string 库定义了大量使用重复模式的函数。由于该类型支持的函数非常多,初次阅读本节是会觉得精神疲累。


Readers might want to skim the remainder of Section 9.6. Once you know what kinds of operations are available, you can return for the details when writing programs that need to use a given operation.

读者可跳过第 9.6 节剩下的内容。一旦知道了有哪些操作可以使用,就可以在编写需要使用这种操作的程序时,才回来阅读其细节。


9.6.1. Other Ways to Construct strings

9.6.1. 构造 string 对象的其他方法

The string class supports all but one of the constructors in Table 9.2 (p. 307). The constructor that takes a single size parameter is not supported for string. We can create a string: as the empty string, by providing no argument; as a copy of another string; from a pair of iterators; or from a count and a character:

string 类支持表 9.2 所列出的几乎所有构造函数,只有一个例外:string 不支持带有单个容器长度作为参数的构造函数。创建 string 对象时:不提供任何参数,则得到空的 string 对象;也可将新对象初始化为另一个 string 对象的副本;或用一对迭代器初始化:或者使用一个计数器和一个字符初始化:

     string s1;           // s1 is the empty string
     string s2(5, 'a');   // s2 == "aaaaa"
     string s3(s2);       // s3 is a copy of s2
     string s4(s3.begin(),
               s3.begin() + s3.size() / 2); // s4 == "aa"

In addition to these constructors, the string type supports three other ways to create a string. We have already used the constructor that takes a pointer to the first character in a null-terminated, character array. There is another constructor that takes a pointer to an element in a character array and a count of how many characters to copy. Because the constructor takes a count, the array does not have to be null-terminated:

除了上述构造函数之外,string 类型还提供了三种其他的方式创建类对象(表 9.13)。在前面的章节中,已经使用过只有一个指针参数的构造函数,该指针指向以空字符结束的字符数组中的第一个元素。另一种构造函数需要一个指向字符数组元素的指针和一个标记要复制多少个字符的计数器作参数。由于该构造函数带有一个计数器,因此数组不必以空字符结束:

     char *cp = "Hiya";            // null-terminated array
     char c_array[] = "World!!!!"; // null-terminated
     char no_null[] = {'H', 'i'};  // not null-terminated

     string s1(cp);             // s1 == "Hiya"
     string s2(c_array, 5);     // s2 == "World"
     string s3(c_array + 5, 4); // s3 == "!!!!"
     string s4(no_null);        // runtime error: no_null not null-terminated
     string s5(no_null, 2);     // ok: s5 == "Hi"

We define s1 using the constructor that takes a pointer to the first character of a null-terminated array. All the characters in that array, up to but not including the terminating null, are copied into the newly created string.

使用只有一个指针参数的构造函数定义 s1,该指针指向以空字符结束的数组中的第一字符。这个数组的所有字符,但不包括结束符 null,都被复制到新创建的 string 对象中。

The initializer for s2 uses the second constructor, taking a pointer and a count. In this case, we start at the character denoted by the pointer and copy as many characters as indicated in the second argument. s2, therefore, is a copy of the first five characters from the array c_array. Remember that when we pass an array as an argument, it is automatically converted to a pointer to its first element. Of course, we are not restricted to passing a pointer to the beginning of the array. We initialize s3 to hold four exclamation points by passing a pointer to the first exclamation point in c_array.

而 s2 的初始化式则通过第二种构造函数实现,它的参数包括一个指针和一个计数器。在这个例子中,从参数指针指向的那个字符开始,连续复制第二个参数指定数目的字符。因此,s2 是 c_array 数组前 5 个字符的副本。记住,将数组作为参数传递时,数组将自动转换为指向其第一个元素的指针。当然,并没有限制非得传递指向数组起点的指针不可。通过给 s3 的构造函数传递指向 c_array 数组中第一个感叹号字符的指针,s3 被初始化为存储 4 个感叹号字符的 string 对象。

The initializers for s4 and s5 are not C-style strings. The definition of s4 is an error. This form of initialization may be called only with a null-terminated array. Passing an array that does not contain a null is a serious error (Section 4.3, p. 130), although it is an error that the compiler cannot detect. What happens at run time is undefined.

s4 和 s5 的初始化式并不是 C 风格字符串。其中,s4 的定义是错误的。调用这种形式的初始化,其参数必须是以空字符结束的数组。将不包含 null 的数组传递给构造函数将导致编译器无法检测的严重错误(第 4.3 节),此类错误在运行时将支发生什么状况并未定义。

The initialization of s5 is fine: That initializer includes a count that says how many characters to copy. As long as the count is within the size of the array, it doesn't matter whether the array is null-terminated.

s5 的初始化则是正确的:初始化式包含了一个计数器,以说明要复制多少个字符用于初始化。该计数器的值必须小于数组的长度,此时,无论数组是否以空字符结束,都没什么关系。

Table 9.13. Additional Ways to Construct strings
9.13. 构造 string 对象的其他方法

string s(cp, n)

Create s as a copy of n characters from array pointed to by cp.

创建一个 string 对象,它被初始化为 cp 所指向数组的前 n 个元素的副本

string s(s2, pos2)

Create s as a copy of characters in the string s2 starting at index pos2. Undefined if pos2 > s2.size().

创建一个 string 对象,它被初始化为一个已存在的 string 对象 s2 中从下标 pos2 开始的字符的副本

string s(s2, pos2, len2)

 

Create s as a copy of len2 characters from s2 starting at index pos2. Undefined if pos2 > s2.size(). Regardless of the value of len2, copies at most s2.size() - pos2 characters.

创建一个 string 对象,它被初始化为 s2 中从下标 pos2 开始的 len2 个字符的副本。如果 pos2 > s2.size(),则该操作未定义,无论 len2 的值是多少,最多只能复制 s2.size() - pos2 个字符

Note: n, len2 and pos2 are all unsigned values.

注意:n、len2 和 pos2 都是 unsigned 值


Using a Substring as the Initializer
用子串做初始化式

The other pair of constructors allow us to create a string as a copy of a substring of the characters in another string:

另一对构造函数使用程序员可以在创建 string 对象时将其初始化为另一个 string 对象的子串。

     string s6(s1, 2);    // s6 == "ya"
     string s7(s1, 0, 2); // s7 == "Hi"
     string s8(s1, 0, 8); // s8 == "Hiya"

The first two arguments are the string from which we want to copy and a starting position. In the two-argument version, the newly created string is initialized with the characters from that position to the end of the string argument. We can also provide a third argument that specifies how many characters to copy. In this case, we copy as many characters as indicated (up to the size of the string), starting at the specified position. For example, when we create s7, we copy two characters from s1, starting at position zero. When we create s8, we copy only four characters, not the requested nine. Regardless of how many characters we ask to copy, the library copies up to the size of the string, but not more.

第一个语句的两个参数指定了要复制的 string 对象及其复制的起点。在两个参数的构造函数版本中,复制 string 对象实参中从指定位置到其末尾的所有字符,用于初始化新创建的 string 对象。还可以为此类构造函数提供第三个参数,用于指定复制字符的个数。在本例中,我们从指定位置开始复制指定数目(最多为 string 对象的长度)的字符数。例如,创建 s7 时,从 s1 中下标为 0 的位置开始复制两个字符;而创建 s8 时,只复制了 4 个字符,而并不是要求的 8 个字符。无论要求复制多少个字符,标准库最多只能复制数目与 string 对象长度相等的字符。

9.6.2. 修改 string 对象的其他方法

Many of the container operations that string supports operate in terms of iterators. For example, erase takes an iterator or iterator range to specify which element(s) to remove from the container. Similarly, the first argument to each version of insert takes an iterator to indicate the position before which to insert the values represented by the other arguments. Although string supports these iterator-based operations, it also supplies operations that work in terms of an index. The index is used to indicate the starting element to erase or the position before which to insert the appropriate values. Table 9.14 lists the operations that are common to both string and the containers; Table 9.15 on the facing page lists the string-only operations.

string 类型支持的许多容器操作在操作时都以迭代器为基础。例如,erase 操作需要一个迭代器或一段迭代器范围作其参数,用于指定从容器中删除的元素。类似地,所有版本的 insert 函数的第一参数都是一个指向插入位置之后的迭代器,而新插入的元素值则由其他参数指定。尽管 string 类型支持这些基于迭代器的操作,它同样也提供以下标为基础的操作。下标用于指定 erase 操作的起始元素,或在其前面 insert 适当值的元素。表 9.14 列出了 string 类型和容器类型共有的操作;而表 9.15 则列出了 string 类型特有的操作。

Table 9.14. string Operations in Common with the Containers
表 9.14 与容器共有的 string 操作

s.insert(p, t)

Insert copy of value t before element referred to by iterator p.

在迭代器 p 指向的元素之前插入一个值为 t 的新元素。返回指向新插入元素的迭代器

Returns an iterator referring to the inserted element.

s.insert(p, n, t)

Insert n copies of t before p. Returns void.

在迭代器 p 指向的元素之前插入 n 个值为 t 的新元素。返回 void

s.insert(p, b, e)

Insert elements in range denoted by iterators b and e before p.

在迭代器 p 指向的元素之前插入迭代器 b 和 e 标记范围内所有的元素。返回 void

Returns void.

s.assign(b, e)

Replace s by elements in range denoted by b and e. For string, returns s, for the containers, returns void.

在迭代器 b 和 e 标记范围内的元素替换 s。对于 string 类型,该操作返回 s;对于容器类型,则返回 void

s.assign(n, t)

Replace s by n copies of value t. For string, returns s, for the containers, returns void.

用值为 t 的 n 个副本替换 s。对于 string 类型,该操作返回 s;对于容器类型,则返回 void

s.erase(p)

Erase element referred to by iteartor p.

删除迭代器 p 指向的元素。返回一个迭代器,指向被删除元素后面的元素

Returns an iterator to the element after the one deleted.

s.erase(b, e)

Remove elements in range denoted by b and e.

删除迭代器 b 和 e 标记范围内所有的元素。返回一个迭代器,指向被删除元素段后面的第一个元素

Returns an iterator to the first element after the range deleted.


Table 9.15. string-Specific Versions
表 9.15 string 类型特有的版本

s.insert(pos, n, c)

Insert n copies of character c before element at index pos.

在下标为 pos 的元素之前插入 n 个字符 c

s.insert(pos, s2)

Insert copy of string s2 before pos.

在下标为 pos 的元素之前插入 string 对象 s2 的副本

s.insert(pos, s2, pos2, len)

 

Insert len characters from s2 starting at pos2 before pos.

在下标为 pos 的元素之前插入 s2 中从下标 pos2 开始的 len 个字符

s.insert(pos, cp, len)

Insert len characters from array pointed to by cp before pos.

在下标为 pos 打元素之前插入 cp 所指向数组的前 len 个字符

s.insert(pos, cp)

Insert copy of null-terminated string pointed to by cp before pos.

在下标为 pos 的元素之前插入 cp 所指向的以空字符结束的字符串副本

s.assign(s2)

Replace s by a copy of s2.

用 s2 的副本替换 s

s.assign(s2, pos2, len)

Replace s by a copy of len characters from s2 starting at index pos2 in s2.

用 s2 中从下标 pos2 开始的 len 个字符副本替换 s

s.assign(cp, len)

Replace s by len characters from array pointed to by cp.

用 cp 所指向数组的前 len 个字符副本替换 s

s.assign(cp)

Replace s by null-terminated array pointed to by cp.

用 cp 所指向的以空字符结束的字符串副本替换 s

s.erase(pos, len)

Erase len characters starting at pos.

删除从下标 pos 开始的 len 个字符

Unless noted otherwise, all operations return a reference to s.

除非特殊声明,上述所有操作都返回 s 的引用


Position-Based Arguments
基于位置的实参

The string-specific versions of these operations take arguments similar to those of the additional constructors covered in the previous section. These operations let us deal with strings positionally and/or let us use arguments that are pointers to character arrays rather than strings.

string 类型为这些操作提供本类型特有的版本,它们接受的实参类似于在前一节介绍的补充构造函数。程序员可通过这些操作基于位置处理 string 对象,并/或使用指向字符数组的指针而不是 string 对象作实参。

For example, all containers let us specify a pair of iterators that denote a range of elements to erase. For strings, we can also specify the range by passing a starting position and count of the number of elements to erase. Assuming s is at least five characters long, we could erase the last five characters as follows:

例如,所有容器都允许程序员指定一对迭代器,用于标记删除(erase)的元素范围。对于 string 类型,还允许通过为 erase 函数传递一个起点位置和删除元素的数目,来指定删除的范围。假设 s 至少有 5 个元素,下面的语句用于删除 s 的最后 5 个字符:

     s.erase(s.size() - 5, 5); // erase last five characters from s

Similarly, we can insert a given number of values in a container before the element referred to by an iterator. In the case of strings, we can specify the insertion point as an index rather than using an iterator:

类似地,对于容器类型,可在迭代器指向的元素之前插入(insert)指定数目的新值。而对于 string 类型,系统还允许使用下标而不是迭代器指定插入位置:

     s.insert(s.size(), 5, '!'); // insert five exclamation points at end of s

Specifying the New Contents
指定新的内容

The characters to insert or assign into the string can be taken from a character array or another string. For example, we can use a null-terminated character array as the value to insert or assign into a string:

在 string 对象中 insert 或 assign 的字符可来自于字符数组或另一个 string 对象。例如,以空字符结束的字符数组可以用作 insert 或 assign 到 string 对象的内容:

     char *cp = "Stately plump Buck";
     string s;
     s.assign(cp, 7);            // s == "Stately"
     s.insert(s.size(), cp + 7); // s == "Stately plump Buck"

Similarly, we can insert a copy of one string into another as follows:

类似地,可如下所示将一个 string 对象的副本插入到另一个 string 对象中:

     s = "some string";
     s2 = "some other string";
     // 3 equivalent ways to insert all the characters from s2 at beginning of s
     // insert iterator range before s.begin()
     s.insert(s.begin(), s2.begin(), s2.end());
     // insert copy of s2 before position 0 in s
     s.insert(0, s2);
     // insert s2.size() characters from s2 starting at s2[0] before s[0]
     s.insert(0, s2, 0, s2.size());

9.6.3. string-Only Operations

9.6.3. 只适用于 string 类型的操作

The string type provides several other operations that the containers do not:

string 类型提供了容器类型不支持其他几种操作,如表 9.16 所示:

  • The substr function that returns a substring of the current string

    substr 函数,返回当前 string 对象的子串。

  • The append and replace functions that modify the string

    append 和 replace 函数,用于修改 string 对象。

  • A family of find functions that search the string

    一系列 find 函数,用于查找 string 对象。

The substr Operation
substr 操作

The substr operation lets us retrieve a substring from a given string. We can pass substr a starting position and a count. It creates a new string that has that many characters, (up to the end of the string) from the target string, starting at the given position:

使用 substr 操作可在指定 string 对象中检索需要的子串。我们可以给 substr 函数传递查找的起点和一个计数器。该函数将生成一个新的 string 对象,包含原目标 string 对象从指定位置开始的若干个字符(字符数目由计数器决定,但最多只能到原 string 对象的最后一个字符):

     string s("hello world");
     // return substring of 5 characters starting at position 6
     string s2 = s.substr(6, 5);   // s2 = world

Alternatively, we could obtain the same result by writing:

可选择另一种方法实现相同的功能:

     // return substring from position 6 to the end of s
     string s3 = s.substr(6);      // s3 = world

Table 9.16. Substring Operation
表 9.16 子串操作

s.substr(pos, n)

Return a string containing n characters from s starting at pos.

返回一个 string 类型的字符串,它包含 s 中从下标 pos 开始的 n 个字符

s.substr(pos)

Return a string containing characters from pos to the end of s.

返回一个 string 类型的字符串,它包含从下标 pos 开始到 s 末尾的所有字符

s.substr()

Return a copy of s.

返回 s 的副本


The append and replace Functions
append 和 replace 函数

There are six overloaded versions of append and ten versions of replace. The append and replace functions are overloaded using the same set of arguments, which are listed in Table 9.18 on the next page. These arguments specify the characters to add to the string. In the case of append, the characters are added at the end of the string. In the replace function, these characters are inserted in place a specified range of existing characters in the string.

string 类型提供了 6 个 append 重载函数版本和 10 个 replace 版本(见表 9.17)。append 和 replace 函数使用了相同的参数集合实现重载。这些参数如表 9.18 所示,用于指定在 string 对象中添加的字符。对于 append 操作,字符将添加在 string 对象的末尾。而 replace 函数则将这些字符插入到指定位置,从而替换 string 对象中一段已存在的字符。

The append operation is a shorthand way of inserting at the end:

     string s("C++ Primer");        // initialize s to "C++ Primer"
     s.append(" 3rd Ed.");          // s == "C++ Primer 3rd Ed."
     // equivalent to s.append(" 3rd Ed.")
     s.insert(s.size(), " 3rd Ed.");

The replace operations remove an indicated range of characters and insert a new set of characters in their place. The replace operations have the same effect as calling erase and insert.

The ten different versions of replace differ from each other in how we specify the characters to remove and in how we specify the characters to insert in their place. The first two arguments specify the range of elements to remove. We can specify the range either with an iterator pair or an index and a count. The remaining arguments specify what new characters to insert.

string 类型为 replace 操作提供了 10 个不同版本,其差别在于以不同的方式指定要删除的字符和要插入的新字符。前两个参数应指定删除的元素范围,可用迭代器对实现,也可用一个下标和一个计数器实现。其他的参数则用于指定插入的新字符。

We can think of replace as a shorthand way of erasing some characters and inserting others in their place:

可将 replace 视为删除一些字符然后在同一位置插入其他内容的捷径:

Table 9.17. Operations to Modify strings (args defined in Table 9.18)
表 9.17 修改 string 对象的操作(args 在表 9.18 中定义)

s.append( args)

Append args to s. Returns reference to s.

将 args 串接在 s 后面。返回 s 引用

s.replace(pos, len, args)

Remove len characters from s starting at pos and replace them by characters formed by args. Returns reference to s.

删除 s 中从下标 pos 开始的 len 个字符,用 args 指定的字符替换之。返回 s 的引用

This version does not take args equal to b2, e2.

在这个版本中,args 不能为 b2,e2

s.replace(b, e, args)

Remove characters in the range denoted by iterators b and e and replace them by args. Returns reference to s.

删除迭代器 b 和 e 标记范围内所有的字符,用 args 替换之。返回 s 的引用

This version does not take args equal to s2, pos2, len2.

在这个版本中,args 不能为 s2,pos2,len2


     // starting at position 11, erase 3 characters and then insert "4th"
     s.replace(11, 3, "4th");          // s == "C++ Primer 4th Ed."
     // equivalent way to replace "3rd" by "4th"
     s.erase(11, 3);                   // s == "C++ Primer Ed."
     s.insert(11, "4th");              // s == "C++ Primer 4th Ed."

There is no requirement that the size of the text removed and inserted be the same.

append 操作提供了在字符串尾部插入的捷径:



In the previous call to replace, the text we inserted happens to be the same size as the text we removed. We could insert a larger or smaller string:

replace 操作用于删除一段指定范围的字符,然后在删除位置插入一组新字符,等效于调用 erase 和 insert 函数。

     s.replace(11, 3, "Fourth"); // s == "C++ Primer Fourth Ed."

In this call we remove three characters but insert six in their place.

在这个例子中,删除了 3 个字符,但在同一个位置却插入了 6 个字符。

Table 9.18. Arguments to append and replace
表 9.18 append 和 replace 操作的参数:args

s2

The string s2.

string 类型的字符串 s2

s2, pos2, len2

up to len2 characters from s2 starting at pos2.

字符串 s2 中从下标 pos2 开始的 len2 个字符

cp

Null-terminated array pointed to by pointer cp.

指针 cp 指向的以空字符结束的数组

cp, len2

up to len2 characters from character array pointed to by cp.

cp 指向的以空字符结束的数组中前 len2 个字符

n, c

n copies of character c.

字符 c 的 n 个副本

b2, e2

Characters in the range formed by iterators b2 and e2.

迭代器 b2 和 e2 标记的范围内所有字符


9.6.4. string Search Operations

9.6.4. string 类型的查找操作

The string class provides six search functions, each named as a variant of find. The operations all return a string::size_type value that is the index of where the match occurred, or a special value named string::npos if there is no match. The string class defines npos as a value that is guaranteed to be greater than any valid index.

string 类提供了 6 种查找函数(表 9.19),每种函数以不同形式的 find 命名。这些操作全都返回 string::size_type 类型的值,以下标形式标记查找匹配所发生的位置;或者返回一个名为 string::npos 的特殊值,说明查找没有匹配。string 类将 npos 定义为保证大于任何有效下标的值。

There are four versions of each of the search operations, each of which takes a different set of arguments. The arguments to the search operations are listed in Table 9.20. Basically, these operations differ as to whether they are looking for a single character, another string, a C-style, null-terminated string, or a given number of characters from a character array.

每种查找操作都有 4 个重载版本,每个版本使用不同的参数集合。表 9.20 列出了查找操作使用的不同参数形式。基本上,这些操作的不同之处在于查找的到底是单个字符、另一个 string 字符串、C 风格的以空字符结束的字符串,还是用字符数组给出的特定数目的字符集合。

Table 9.19. string Search Operations (Arguments in Table 9.20)

s.find( args)

Find first occurrence of args in s.

在 s 中查找 args 的第一次出现

s.rfind( args)

Find last occurrence of args in s.

在 s 中查找 args 的最后一次出现

s.find_first_of( args)

Find first occurrence of any character from args in s.

在 s 中查找 args 的任意字符的第一次出现

s.find_last_of( args)

Find last occurrence of any character from args in s.

在 s 中查找 args 的任意字符的最后一次出现

s.find_first_not_of( args)

Find first character in s that is not in args.

在 s 中查找第一个不属于 args 的字符

s.find_last_not_of( args)

Find last character in s that is not in args.

在 s 中查找最后一个不属于 args 的字符


Table 9.20. Arguments to string find Operations
string 类型提供的 find 操作的参数

c, pos

Look for the character c starting at position pos in s. pos defaults to 0.

在 s 中,从下标 pos 标记的位置开始,查找字符 c。pos 的默认值为 0

s2, pos

Look for the string s2 starting at position pos in s. pos defaults to 0.

在 s 中,从下标 pos 标记的位置开始,查找 string 对象 s2。pos 的默认值为 0

cp, pos

Look for the C-style null-terminated string pointed to by the pointer cp.

在 s 中,从下标 pos 标记的位置形参,查找指针 cp 所指向的 C 风格的以空字符结束的字符串。pos 的默认值为 0

Start looking starting at position pos in s. pos defaults to 0.

cp, pos, n

Look for the first n characters in the array pointed to by the pointer cp.

在 s 中,从下标 pos 标记的位置开始,查找指针 cp 所指向数组的前 n 个字符。pos 和 n 都没有默认值

Start looking starting at position pos in s. No default for pos or n.


Finding an Exact Match
精确匹配的查找

The simplest of the search operations is the find function. It looks for its argument and returns the index of the first match that is found, or npos if there is no match:

最简单的查找操作是 find 函数,用于寻找实参指定的内容。如果找到的话,则返回第一次匹配的下标值;如果找不到,则返回 npos:

     string name("AnnaBelle");
     string::size_type pos1 = name.find("Anna"); // pos1 == 0

Returns 0, the index at which the substring "Anna" is found in "AnnaBelle".

返回 0,这是子串“Anna”位于字符串“AnnaBelle”中的下标。

By default, the find operations (and other string operations that deal with characters) use the built-in operators to compare characters in the string. As a result, these operations (and other string operations) are case sensitive.

默认情况下,find 操作(以及其他处理字符的 string 操作)使用内置操作符比较 string 字符串中的字符。因此,这些操作(以及其他 string 操作)都区分字母的大小写。



When we look for a value in the string, case matters:

以下程序寻找 string 对象中的某个值,字母的大小写影响了程序结果:

     string lowercase("annabelle");
     pos1 = lowercase.find("Anna"); // pos1 == npos

This code will set pos2 to nposthe string Anna does not match anna.

这段代码使 pos1 的值为 npos ——字符串 Anna 与 anna 不匹配

The find operations return a string::size_type. Use an object of that type to hold the return from find.

find 操作的返回类型是 string::size_type,请使用该类型的对象存储 find 的返回值。



Find Any Character
查找任意字符

A slightly more complicated problem would be if we wanted to match any character in our search string. For example, the following locates the first digit within name:

如果在查找字符串时希望匹配任意指定的字符,则实现起来稍微复杂一点。例如,下面的程序要在 name 中寻找并定位第一个数字:

     string numerics("0123456789");
     string name("r2d2");
     string::size_type pos = name.find_first_of(numerics);
     cout << "found number at index: " << pos
          << " element is "  << name[pos] << endl;

In this example, pos is set to a value of 1 (the elements of a string, remember, are indexed beginning at 0).

在这个例子中,pos 的值被设置为 1(记住,string 对象的元素下标从 0 开始计数)。

Specifying Where to Start the Search
指定查找的起点

We can pass an optional starting position to the find operations. This optional argument indicates the index 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. We could rewrite our search of "r2d2" to find all the numbers in name:

程序员可以给 find 操作传递一个可选的起点位置实参,用于指定开始查找的下标位置,该位置实参的默认值为 0。通常的编程模式是使用这个可选的实参循环查找 string 对象中所有的匹配。下面的程序重写了查找“r2d2”的程序,以便找出 name 字符串中出现的所有数字:

     string::size_type pos = 0;
     // each trip reset pos to the next instance in name
     while ((pos = name.find_first_of(numerics, pos))
                   != string::npos) {
         cout << "found number at index: " << pos
              << " element is " << name[pos] << endl;
         ++pos; // move to the next character
     }

In this case, we initialize pos to zero so that on the first trip through the while name is searched, beginning at position 0. The condition in the while resets pos to the index of the first number encountered, starting from the current value of pos. As long as the return from find_first_of is a valid index, we print our result and increment pos.

在这个例子中,首先将 pos 初始化为 0,使第一次循环从 0 号元素开始查找 name。while 的循环条件实现两个功能:从当前 pos 位置开始查找,并将找到的第一个数字出现的下标值赋给 pos。当 find_first_of 函数返回有效的下标值时,输出此次查找的结果,并且让 pos 加 1。

Had we neglected to increment pos at the end of this loop, then it would never terminate. To see why, consider what would happen if we didn't. 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!

如果漏掉了循环体末尾让 pos 加 1 的语句,那么循环永远都不会结束。考虑没有该操作时,会发生什么情况?第二次循环时,从 pos 标记的位置开始查找,而此时 pos 标记的就是一个数字,于是 find_first_of 函数将(不断重复地)返回同一个 pos 值。

It is essential that we increment pos. Doing so ensures that we start looking for the next number at a point after the number we just found.



Looking for a Nonmatch
寻找不匹配点

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 non-numeric character of a string, we can write

除了寻找匹配的位置外,还可以调用 find_first_not_of 函数查找第一个与实参不匹配的位置。例如,如果要在 string 对象中寻找第一个非数字字符,可以如下编写程序:

     string numbers("0123456789");
     string dept("03714p3");

     // returns 5, which is the index to the character 'p'
     string::size_type pos = dept.find_first_not_of(numbers);

Searching Backward
反向查找

Each of the find operations that we've seen so far executes left to right. The library provides an analogous set of operations that look through the string from right to left. The rfind member searches for the lastthat is, rightmostoccurrence of the indicated substring:

迄今为止,我们使用的所有 find 操作都是从左向右查找的。除此之外,标准库还提供了一组类似的从右向左查找 string 对象的操作。rfind 成员函数用于寻找最后一个——也就是是最右边的——指定子串出现的位置:

     string river("Mississippi");
     string::size_type first_pos = river.find("is"); // returns 1
     string::size_type 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".

find 函数返回下标 1,标记 river 字符串中第一个“is”的出现位置;而 rfind 函数返回最后一个匹配的位置,而并不是第一个。

The find_last Functions

The find_last functions operate like the corresponding 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_of 函数查找与目标字符串的任意字符匹配的最后一个字符。

  • find_last_not_of searches for the last character that does not match any element of the search string.

    find_last_not_of 函数查找最后一个不能跟目标字符串的任何字符匹配的字符。

Each of these operations takes an optional second argument indicating the position within the string to begin searching.

这两个操作都提供第二个参数,这个参数是可选的,用于指定在 string 对象中开始查找的位置。

9.6.5. Comparing strings

9.6.5.

As we saw in Section 3.2.3 (p. 85), the string type defines all the relational operators so that we can compare two strings for equality (==), inequality (!=), and the less- or greater-than operations (<, <=, >, >=). Comparison between strings is lexicographicalthat is, string comparison is the same as a case-sensitive, dictionary ordering:

正如在第 3.2.3 节所看到的,string 类型定义了所有关系操作符,使程序员可以比较两个 string 对象是否相等(==)、不等(!=),以及实现小于或大于(<<=>>=)运算。string 对象采用字典顺序比较,也就是说,string 对象的比较与大小写敏感的字典顺序比较相同:

     string cobol_program_crash("abend");
     string cplus_program_crash("abort");

Exercises Section 9.6.4

Exercise 9.38:

Write a program that, given the string

已知有如下 string 对象:

     "ab2c3d7R4E6"

finds each numeric character and then each alphabetic character. Write two versions of the program. The first should use find_first_of, and the second find_first_not_of.

编写程序寻找该字符串中所有的数字字符,然后再寻找所有的字母字符。以两种版本编写该程序:第一个版本使用 find_first_of 函数,而第二个版本则使用 find_first_not_of 函数。

Exercise 9.39:

Write a program that, given the strings

已知有如下 string 对象:

     string line1 = "We were her pride of 10 she named us:";
     string line2 = "Benjamin, Phoenix, the Prodigal"
     string line3 = "and perspicacious pacific Suzanne";

     string sentence = line1 + ' ' + line2 + ' ' + line3;

counts the number of words in sentence and identifies the largest and smallest words. If several words have the largest or smallest length, report all of them.

编写程序计算 sentence 中有多少个单词,并指出其中最长和最短的单词。如果有多个最长或最短的单词,则将它们全部输出。


Here cobol_program_crash is less than the cplus_program_crash. The relational operators compare two strings character by character until reaching a position where the two strings differ. The overall comparison of the strings depends on the comparison between these unequal characters. In this case, the first unequal characters are 'e' and 'o'. The letter 'e' occurs before (is less than) 'o' in the English alphabet and so "abend" is less than "abort". If the strings are of different length, and one string is a substring of the other, then the shorter string is less than the longer.

操作符逐个字符地进行比较,直到比较到某个位置上,两个 string 对象对应的字符不相同为止。string 对象的整个比较依赖于不相同字符之间的比较。在本例中,第一个不相等的字符是‘e’和‘o’。由于在英文字母表中,‘e’出现得比‘o’早(即‘e’小于‘o’),于是“abend”小于“abort”。如果要比较的两个 string 对象长度不相同,而且一个 string 对象是另一个 string 对象的子串,则较短的 string 对象小于较长的 string 对象。

The compare Functions
compare 函数

In addition to the relational operators, string provides a set of compare operations that perform lexicographical comparions. The results of these operations are similar to the C library strcmp function (Section 4.3, p. 132). Given

除了关系操作符,string 类型还提供了一组 compare 操作(表 9.21),用于实现字典顺序的比较。这些操作的结果类似于 C 语言中的库函数 strcmp(第 4.3 节)。假设有语句:

     s1.compare (args);

compare returns one of three possible values:

compare 函数返回下面列出的三种可能值之一:

  1. A positive value if s1 is greater than the string represented by args

    正数,此时 s1 大于 args 所代表的 string 对象。

  2. A negative value if s1 is less than the string represented by args

    负数,此时 s1 小于 args 所代表的 string 对象。

  3. 0 if s1 is equal to the string represented by args

    0,此时 s1 恰好等于 args 所代表的 string 对象。

For example

例如:

     // returns a negative value
     cobol_program_crash.compare(cplus_program_crash);
     // returns a positive value
     cplus_program_crash.compare(cobol_program_crash);

Table 9.21. string compare Operations
表 9.21 string 类型 compare 操作

s.compare(s2)

Compare s to s2.

比较 s 和 s2

s.compare(pos1, n1, s2)

 

Compares n1 characters starting at pos1 from s to s2.

让 s 中从 pos 下标位置开始的 n1 个字符与 s2 做比较

s.compare(pos1, n1, s2, pos2, n2)

 

Compares n1 characters starting at pos1 from s to the n2 characters starting at pos2 in s2.

让 s 中从 pos1 下标位置开始的 n1 个字符与 s2 中从 pos2 下标位置开始的 n2 个字符做比较

s.compare(cp)

Compares s to the null-terminated string pointed to by cp.

比较 s 和 cp 所指向的以空字符结束的字符串

s.compare(pos1, n1, cp)

 

Compares n1 characters starting at pos1 from s to cp.

让 s 中从 pos1 下标位置开始的 n1 个字符与 cp 所指向的字符串做比较

s.compare(pos1, n1, cp, n2)

 

Compares n1 characters starting at pos1 from s to n2 characters starting from the pointer cp.

让 s 中从 pos1 下标位置开始的 n1 个字符与 cp 所指向的字符串的前 n2 个字符做比较


The overloaded set of six compare operations allows us to compare a substring of either one or both strings for comparison. They also let us compare a string to a character array or portion thereof:

compare 操作提供了 6 种重载函数版本,以方便程序员实现一个或两个 string 对象的子串的比较,以及 string 对象与字符数组或其中某一部分的比较:

     char second_ed[] = "C++ Primer, 2nd Edition";
     string third_ed("C++ Primer, 3rd Edition");
     string fourth_ed("C++ Primer, 4th Edition");

     // compares C++ library string to C-style string
     fourth_ed.compare(second_ed); // ok, second_ed is null-terminated

     // compare substrings of fourth_ed and third_ed
     fourth_ed.compare(fourth_ed.find("4th"), 3,
                       third_ed, third_ed.find("3rd"), 3);

The second call to compare is the most interesting. This call uses the version of compare that takes five arguments. We use find to locate the position of the beginning of the substring "4th". We compare three characters starting at that position to a substring from third_ed. That substring begins at the position returned from find when looking for "3rd" and again we compare three characters. Essentially, this call compares "4th" to "3rd".

我们对第二个 compare 函数的调用更感兴趣。这个调用使用了具有 5 个参数的 compare 函数版本。先调用 find 函数找到子串“4th”的起点。让从此起点开始的 3 个字符与 third_ed 的子串做比较。而 third_ed 的子串起始于 find 函数找到的“3rd”的起点,同样取其随后的 3 个字符参加比较。可见这个语句本质上比较的是“4th”和“3rd”。

Exercises Section 9.6.5

Exercise 9.40:

Write a program that accepts the following two strings:

编写程序接收下列两个 string 对象:

     string q1("When lilacs last in the dooryard bloom'd");
     string q2("The child is father of the man");

Using the assign and append operations, create the string

然后使用 assign 和 append 操作,创建 string 对象:

     string sentence("The child is in the dooryard");

Exercise 9.41:

Write a program that, given the strings

已知有如下 string 对象:

     string generic1("Dear Ms Daisy:");
     string generic2("MrsMsMissPeople");

implements the function

编写程序实现下面函数:

     string greet(string form, string lastname, string title,
                  string::size_type pos, int length);

using the replace operations, where lastname replaces Daisy and pos indexes into generic2 of length characters replacing Ms. For example, the following

该函数使用 replace 操作实现以下功能:对于字符串 form,将其中的 Daisy 替换为 lastname,将其中的 Ms 替换为字符串 generic2 中从 pos 下标开始的 length 个字符。例如,下面的语句:

     string lastName("AnnaP");
     string salute = greet(generic1, lastName, generic2, 5, 4);

returns the string

将返回字符串:

     Dear Miss AnnaP:


Team LiB
Previous Section Next Section