字符串基本使用
字符串说白了就是字符类型的数组,里面可以存储字符型的数据,元素的下标从 0
开始。
在C语言风格中,使用字符数组 char[]
来操作,在C++风格中,一般使用 string
来操作,此处就着重以 string
来进行讲解。
使用 string
时,需要导入 string
或者 cstring
头文件,当然如果导入 bits/stdc++.h
万能头文件就不用管了。
1.定义字符串
格式如下所示:
string 变量名;
例如:
string s;
定义了一个字符串,变量名为 s
。
2.字符串输入、输出、遍历
下方的例子都以 要操作的字符串变量名是 s
为前提。
输入:如果字符串不带空格,cin >> s;
,一定要注意这样输入的字符串的下标是从
输出:可以直接 cout
,cout << s;
,也可以通过循环遍历来进行输出。
获取长度:一般题目中输入字符串时会给出,若没给出,可以通过 s.size()
或者 s.length()
来进行获取。这两个方法并没区别,一般为了键盘的寿命,个人更偏向使用 s.size()
。
需要注意的是这两个方法返回的实际上是 string::size_type
类型,是一个无符号整型,如果你需要进行长度的减法之类的操作,建议使用一个 int
型变量存储长度,使用这个变量来进行操作。
遍历:下标范围为 0~s.size()-1
,所以正序遍历就是循环列出 0~s.size()-1
的数字,在循环中对 s[i]
进行操作即可。
下方这个例子,演示了字符串的简单输入与遍历输出:
#include <bits/stdc++.h>
using namespace std;
string s; // 字符串的定义
int len;
int main() {
cin >> s;
len = s.size(); // s.size() 获取这个字符串的长度,建议把长度存为带符号整数类型。
cout << "直接通过cout输出:" << s << '\n';
// 下标从 0开始,长度为 len 的字符串,0~len-1
cout << "通过循环+下标的形式输出:";
for (int i=0; i<len; i++) {
cout << s[i];
}
return 0;
}
3.带空格的字符串的处理
可以分成两种方式来进行输入:
需要保留空格进行处理的,可以使用 getline(cin, 字符串变量)
,这段代码可以把一整行的数据都输入到 s
中,包括空格。例如:
string s;
getline(cin, s); // 假设是 hello world! hahaha 666.
cout << s; // 输出就是 hello world! hahaha 666. 空格会保留下来。
getline
的默认终止符是 \n
,也就意味着,当遇到换行时,它会终止这一次的输入。终止符也可以设置为其他字符,不过在普及组用得是不多的,这里不多做拓展。
另外要注意的是,getline
和 cin
如果一起用,是会出现问题的,如果你写了如下这段代码:
int n;
string s;
cin >> n;
getline(cin, s);
那么你就惨了,下面的 s
可能无法正常读入。原理这里不多赘述,解决办法就是尽量避免这样做,或者在 cin
和 getline
之间加入一行 cin.ignore();
。
不需要保留空格处理的,非常典型的是 给你一段话,单词都是以空格分开,要对这些单词进行操作,而空格只是来分隔这些单词,可以使用 while
+ cin
,例如:
string s;
while (cin >> s) { // 假设输入的是 hello world! hahaha 666.
cout << s << '\n';
}
这段代码会把字符串自动以空格或者换行为作为分隔符,将其他字符分别进行输入。上面这段代码的运行结果会是:
hello
world!
hahaha
666.
所以对于提取单词,这个方式是比较容易进行处理的。
需要注意的是,这种输入方式在控制台进行输入时,是不会自动结束的,它会一直等待你输入数据,如果你已经完成了输入,那么请按下 ctrl+Z
(苹果用户按 command+Z
),然后再按回车即可。而在代码提交到测评机上时,你不用担心它会死循环,当读入完输入文件的最后一个字符后,下一次会读到终止符,它会自动停止。
当然,也有很多其他的方式,诸如 getchar()
等,但普及组掌握以上两种输入即可,学得多了反而容易混淆。
4.课上例题
字符串常用方法&技巧
下方的例子都以 要操作的字符串变量名是 s
为前提。
1.字符筛选
获取字符串 s
的长度:s.size()
判断字符 s[i]
是否是字母:isalpha(s[i])
或者 s[i]>='A' and s[i]<='Z' or s[i]>='a' and s[i]<='z'
,更推荐大家理解后面的方法,因为字符存储的本质都是 ASCII 码,所以在这个 ASCII 码范围内,自然就是字母。
判断字符 s[i]
是否是数字:isdigit(s[i])
或者 s[i]>='0' and s[i]<='9'
。
判断字符 s[i]
是否是大写字母:isupper(s[i])
或者 s[i]>='A' and s[i]<='Z'
。
判断字符 s[i]
是否是小写字母:islower(s[i])
或者 s[i]>='a' and s[i]<='z'
。
对于上述技巧,这里有一个 DEMO 演示,推荐大家跟着一起把代码写一遍,判断大写字母和小写字母请自行尝试。
#include <bits/stdc++.h>
using namespace std;
string s;
int len;
int main() {
cin >> s; // 假设输入的字符串是 ab1234ABC%
len = s.size(); // 长度应该为 10
cout << "长度:" << len << '\n';
for (int i=0; i<len; i++) { // 遍历字符串
// 判断是否是数字
if (s[i] >= '0' and s[i] <= '9') cout << "数字:" << s[i] << '\n';
// 判断是否是字母
else if (isalpha(s[i])) cout << "字母:" << s[i] << '\n';
// 都不是就是符号
else cout << "符号:" << s[i] << '\n';
}
return 0;
}
2.大小写相关
单个字符 s[i]
小写转大写:判断是小写字母 然后 s[i] -= 32
或者 直接 s[i] = toupper(s[i])
。
单个字符 s[i]
大写转小写:判断是大写字母 然后 s[i] += 32
或者 直接 s[i] = tolower(s[i])
。
整个字符串中的字母全部转成小写:
方式一:遍历字符串,判断是否是大写字母,是则转换成小写。
方式二:transform(s.begin(), s.end(), s.begin(), ::tolower)
。这个方法可以直接把整个 s
中的字母都转成小写,并重新存储到 s
中。 如果需要存储到其他字符串中(例如 a
),则把第三处的 s.begin()
改成 a.begin()
。
整个字符串中的字母全部转大写:
方式一:遍历字符串,判断是否是小写字母,是则转换成大写。
方式二:transform(s.begin(), s.end(), s.begin(), ::toupper)
。这个方法可以直接把整个 s
中的字母都转成大写,并重新存储到 s
中。 如果需要存储到其他字符串中(例如 a
),则把第三处的 s.begin()
改成 a.begin()
。
此处进行了大小写转换的 DEMO 演示。
#include <bits/stdc++.h>
using namespace std;
string s;
int len;
int main() {
cin >> s; // 假设输入的字符串是 ab1234ABC%
len = s.size();
for (int i=0; i<len; i++) { // 遍历字符串
// 如果原本是小写字母,转为大写字母
if (islower(s[i])) s[i] = toupper(s[i]);
// 如果原本是大写字母,转为小写字母
else if (s[i] >= 'A' and s[i] <= 'Z') s[i] += 32;
}
cout << "大小写互换:" << s << '\n'; // 结果应为 AB1234abc%
transform(s.begin(), s.end(), s.begin(), ::tolower);
cout << "全转为小写:" << s << '\n'; // 结果应为 ab1234abc%
transform(s.begin(), s.end(), s.begin(), ::toupper);
cout << "全转为大写:" << s << '\n'; // 结果应为 AB1234ABC%
return 0;
}
3.字符串处理
判断字符串 a
和 b
是否相等
方式一:遍历两个字符串然后逐个比较。
方式二:直接判断 a == b
。同样也可以用 >
、<
等来比较字符串的大小,字符串的比较是 从第一个字符开始按位比较,如果某一位的ASCII码值不同,谁的值更大就哪个字符串更大。
字符串拼接
在字符串 s
后面拼上新的字符或者别的字符串,可以直接使用 +=
运算符,例如:
s += 'a';
,s += "abcd";
,s += s2; // s2指另一个字符串变量
。
查找子串
查找字符串 a
在 字符串 b
中 第一次出现的位置,或者判断是否出现(即 a
是否是 b
的子串。)
方式一:循环枚举可能的 第一次出现的位置,然后逐个判断是否每一个字符都相等。
方式二:b.find(a)
,返回 a
在 b
中第一次出现的位置,如果 a
没有在 b
中出现过,则返回 string::npos
,转为有符号整数后就是 -1
。
下面是查找字符串的 DEMO。
#include <bits/stdc++.h>
using namespace std;
string s1, s2, s3;
int main() {
// 假设 s1 是 abcdecde,s2 是 cde,s3 是 klm
cin >> s1 >> s2 >> s3;
cout << s1.find(s2) << '\n'; // 输出为 2,因为第一次出现的位置是从 2 开始
cout << s1.find(s3) << '\n'; // 是一个很大的数字,因为返回的是无符号整型,转为int后其实是-1
int flag = s1.find(s3);
cout << flag << '\n'; // -1
return 0;
}
字符串截取
字符串截取,截取出字符串中的某一段。
方式一:循环遍历这一段字符串,比如要截取
方式二:利用 substr()
方法。以下是 DEMO 演示:
string s = "abcdefg", s1, s2;
s1 = s.substr(2); // 从下标2开始,截取后面的所有字符,即cdefg
s2 = s.substr(3, 2); // 从下标3开始,截取两个字符,即de
字符串与int转换
string
转 int
,把一个字符串格式的数字转成 int
类型。
方式一,循环遍历,按位提取出数字,用一个整型变量来存储提取出来的数字。
string s = "114514";
int num = 0, len = s.size();
for (int i=0; i<len; i++) {
/*
核心为这个拼接公式,为什么num每次都要乘10呢,可以想象一下,num里面已经存了11,现在要把4拼进
去,变成114,怎么拼呢,自然是 11*10+4。
而为什么每次加 s[i] 都要减去 '0' 呢,因为字符类型本质是ASCII码值,比如字符 '0' 的ASCII码
是48,如果要正确的把数字0拼进去,自然要减去48,其他数字同理。
*/
num = num*10 + (s[i]-'0');
}
方式二,使用 stoi
,使用时需要注意,字符串里面必须是纯数字组成的。上面那段代码可以这样写:int num = stoi(s)
。
int
转 string
,把数字转成 string
类型,可以使用 to_string()
方法,例如:
int num = 114514;
string s = to_string(num); // s = "114514"
当然这里也可以使用 数位分离+字符串拼接 来做,不过还是偏麻烦的,这里就不再演示了,感兴趣可以自行实现。
4.string的常用操作函数
红色部分为常用方法
- =, s.assign() // 赋以新值
- swap(s1, s2) // 交换两个字符串s1,s2的内容
- +=, s.append(), s.push_back() // 在尾部添加字符; pop_back()删除尾部字符。
- s.insert(i, s1) // 在s的下标i处插入字符或字符串s1
- s.erase(i, n) // 删除从下标i开始的n个字符
- s.clear() // 删除全部字符
- s.replace(i, n, t) // 将s从下标i开始的连续n个字符替换为t
- + // 串联字符串 s1 + s2
- ==,!=,<,<=,>,>=,compare() // 比较字符串
- s.size(),length() // 返回字符数量,如s1.size()
- s.max_size() // 返回string类型对象支持的最大字符数
- s.empty() // 判断字符串是否为空,空返回1,否则返回0
- s.capacity() // 返回重新分配之前的字符容量
- reserve() // 保留一定量内存以容纳一定数量的字符
- [], at() // 存取单一字符
- >>,getline() // 从stream读取某值
- << // 将某值写入stream
- copy() // 将某值赋值为一个C_string
- s.c_str() // 返回一个指向正规C字符串(C_string)的指针 内容与本string串相同 有
\0
- s.data() // 将内容以字符数组形式返回 无
\0
- s.substr(i, n) // 返回子字符串
- begin() end() // 提供类似STL的迭代器支持
- rbegin() rend() // 逆向迭代器
- count(s.begin(), s.end(), 'c') // 查找c字符在s中出现的次数
- s.find() //找某个子串是否在s中
- reverse(s.begin(),s.end()) // 反转s
- sort(s.begin(), s.end()) // 按字典序排序s
- stoi(s) //将s转为int,需保证字符串为纯数字,否则无法正确转换,返回int
- to_string(n) // 将int n转换为string,返回string对象