string

string 是什么

std::string 是在标准库 <string>(注意不是 C 语言中的 <string.h> 库)中提供的一个类,本质上是 std::basic_string<char> 的别称。

为什么要使用 string

在 C 语言中,提供了字符串的操作,但只能通过字符数组的方式来实现字符串。而 string 则是一个简单的类,使用简单,在 OI 竞赛中被广泛使用。并且相较于其他 STL 容器,string 的常数可以算是非常优秀的,基本与字符数组不相上下。

string 可以动态分配空间

和许多 STL 容器相同,string 能动态分配空间,这使得我们可以直接使用 std::cin 来输入,但其速度则同样较慢。这一点也同样让我们不必为内存而烦恼。

string 重载了加法运算符和比较运算符

string 的加法运算符可以直接拼接两个字符串或一个字符串和一个字符。和 std::vector 类似,string 重载了比较运算符,同样是按字典序比较的,所以我们可以直接调用 std::sort 对若干字符串进行排序。

使用方法

下面介绍 string 的基本操作,具体可看 C++ 文档

声明

1
std::string s;

转 char 数组

在 C 语言里,也有很多字符串的函数,但是它们的参数都是 char 指针类型的,为了方便使用,string 有两个成员函数能够将自己转换为 char 指针——data()/c_str()(它们几乎是一样的,但最好使用 c_str(),因为 c_str() 保证末尾有空字符,而 data() 则不保证),如:

1
2
3
printf("%s", s);          // 编译错误
printf("%s", s.data());   // 编译通过,但是是 undefined behavior
printf("%s", s.c_str());  // 一定能够正确输出

获取长度

很多函数都可以返回 string 的长度:

1
2
3
printf("s 的长度为 %lu", s.size());
printf("s 的长度为 %lu", s.length());
printf("s 的长度为 %lu", strlen(s.c_str()));
这些函数的复杂度

strlen() 的复杂度一定是与字符串长度线性相关的。

size()length() 的复杂度在 C++98 中没有指定,在 C++11 中被指定为常数复杂度。但在常见的编译器上,即便是 C++98,这两个函数的复杂度也是常数。

Warning

这三个函数(以及下面将要提到的 find 函数)的返回值类型都是 size_tunsigned long)。因此,这些返回值不支持直接与负数比较或运算,建议在需要时进行强制转换。

寻找某字符(串)第一次出现的位置

find(str,pos) 函数可以用来查找字符串中一个字符/字符串在 pos(含)之后第一次出现的位置(若不传参给 pos 则默认为 0)。如果没有出现,则返回 string::npos(被定义为 -1,但类型仍为 size_t/unsigned long)。

示例:

1
2
3
4
5
6
7
string s = "OI Wiki", t = "OI", u = "i";
int pos = 5;
printf("字符 I 在 s 的 %lu 位置第一次出现\n", s.find('I'));
printf("字符 a 在 s 的 %lu 位置第一次出现\n", s.find('a'));
printf("字符 a 在 s 的 %d 位置第一次出现\n", s.find('a'));
printf("字符串 t 在 s 的 %lu 位置第一次出现\n", s.find(t));
printf("在 s 中自 pos 位置起字符串 u 第一次出现在 %lu 位置", s.find(u, pos));

输出:

1
2
3
4
5
字符 I 在 s 的 1 位置第一次出现
字符 a 在 s 的 18446744073709551615 位置第一次出现 // 即为 size_t(-1),具体数值与平台有关。
字符 a 在 s 的 -1 位置第一次出现 // 强制转换为 int 类型则正常输出 -1
字符串 t 在 s 的 0 位置第一次出现
在 s 中自 pos 位置起字符串 u 第一次出现在 6 位置

截取子串

substr(pos, len) 函数的参数返回从 pos 位置开始截取最多 len 个字符组成的字符串(如果从 pos 开始的后缀长度不足 len 则截取这个后缀)。

示例:

1
2
3
4
5
string s = "OI Wiki", t = "OI";
printf("从字符串 s 的第四位开始的最多三个字符构成的子串是 %s\n",
       s.substr(3, 3).c_str());
printf("从字符串 t 的第二位开始的最多三个字符构成的子串是 %s",
       t.substr(1, 3).c_str());

输出:

1
2
从字符串 s 的第二位开始的最多三个字符构成的子串是 Wik
从字符串 t 的第二位开始的最多三个字符构成的子串是 I

插入/删除字符(串)

insert(index,count,ch)insert(index,str) 是比较常见的插入函数。它们分别表示在 index 处连续插入 count 次字符串 ch 和插入字符串 str

erase(index,count) 函数将字符串 index 位置开始(含)的 count 个字符删除(若不传参给 count 则表示删去 count 位置及以后的所有字符)。

示例:

1
2
3
4
5
6
7
8
9
string s = "OI Wiki", t = " Wiki";
char u = '!';
s.erase(2);
printf("从字符串 s 的第三位开始删去所有字符后得到的字符串是 %s\n", s.c_str());
s.insert(2, t);
printf("在字符串 s 的第三位处插入字符串 t 后得到的字符串是 %s\n", s.c_str());
s.insert(7, 3, u);
printf("在字符串 s 的第八位处连续插入 3 次字符串 u 后得到的字符串是 %s",
       s.c_str());

输出:

1
2
3
从字符串 s 的第三位开始删去所有字符后得到的字符串是 OI
在字符串 s 的第三位处插入字符串 t 后得到的字符串是 OI Wiki
在字符串 s 的第八位处连续插入 3 次字符串 u 后得到的字符串是 OI Wiki!!!

替换字符(串)

replace(pos,count,str)replace(first,last,str) 是比较常见的替换函数。它们分别表示将从 pos 位置开始 count 个字符的子串替换为 str 以及将以 first 开始(含)、last 结束(不含)的子串替换为 str,其中 firstlast 均为迭代器。

示例:

1
2
3
4
5
string s = "OI Wiki";
s.replace(2, 5, "");
printf("将字符串 s 的第 3~7 位替换为空串后得到的字符串是 %s\n", s.c_str());
s.replace(s.begin(), s.begin() + 2, "NOI");
printf("将字符串 s 的前两位替换为 NOI 后得到的字符串是 %s", s.c_str());

输出:

1
2
将字符串 s 的第 3~7 位替换为空串后得到的字符串是 OI
将字符串 s 的前两位替换为 NOI 后得到的字符串是 NOI