跳转至

字符串的应用

下面处理英文字母、数字和常见符号,字符串长度能放进 int。代码片段分别使用,需要 <iostream>、<string> 和 using namespace std;。

读入一整行

cin >> s 遇到空白就停;要读入一整行,包括空格,用 getline。

string s;
getline(cin, s);

cout << s;

getline 读走换行,但不把换行存进 s;读到空行,s 就是空串。

和 cin >> 混用,注意残留的换行。 第一行输入 n 后直接换行,第二行输入句子,可以这样写:

int n;
cin >> n;
getchar();

string s;
getline(cin, s);

getchar() 读走一个字符,这里读走换行,需要 <cstdio>。

n 后面别留空格,否则读走的是空格。

不处理换行,getline 可能读到空串,看起来像“没有输入就结束了”。

统计字符

输入一个由大小写字母、数字组成的字符串,分别统计每个字符出现的次数。

int cntA[26], cnta[26], cnt[10]; // 开全局,默认都是0
string s;
cin >> s;

for (char c : s) {
    if (c >= 'A' && c <= 'Z') cntA[c - 'A']++;
    else if (c >= 'a' && c <= 'z') cnta[c - 'a']++;
    else if (c >= '0' && c <= '9') cnt[c - '0']++;
}

'A' 减去 'A' 得到 0,'B' 减去 'A' 得到 1,正好对应计数数组的下标。

统计完以后,按题目要求输出。比如输出 26 个大写字母的次数:

for (int i = 0; i < 26; i++) cout << cntA[i] << ' ';

大小写转换

把大写字母转成小写,其他字符保持原样。

string s;
getline(cin, s);

int len = (int)s.size();
for (int i = 0; i < len; i++)
    if (s[i] >= 'A' && s[i] <= 'Z') s[i] += 'a' - 'A';

cout << s;

'a' - 'A' 是大小写字母的编码差值。

补充:范围循环修改字符,用 char &c。 学过引用后再看。

string s;
getline(cin, s);

for (char &c : s)
    if (c >= 'A' && c <= 'Z') c += 'a' - 'A';

cout << s;

char &c 能修改原字符;char c 改的是副本,s 不变。

过滤空格

直接输出过滤后的内容

string s;
getline(cin, s);

for (char c : s)
    if (c != ' ') cout << c;

存进一个新字符串

string s, s2;
getline(cin, s);

for (char c : s)
    if (c != ' ') s2 += c;

cout << s2;

这里只去掉普通空格 ' ',不是删除所有空白字符。

抠单词操作(重点)

1143:最长最短单词

按空格、逗号抠出单词,打擂台,找第一个最长单词和第一个最短单词。保证至少有一个单词。

#include <iostream>
#include <string>

using namespace std;

int main() {
    string s;
    getline(cin, s);

    int len = (int)s.size();
    int i = 0, maxn = -1, minn = len + 1;
    string maxt, mint;
    while (i < len) {
        if (s[i] == ' ' || s[i] == ',') {
            i++;
            continue;
        }

        string t;
        while (i < len && s[i] != ' ' && s[i] != ',') t += s[i++];

        int cnt = (int)t.size();
        if (cnt > maxn) {
            maxn = cnt;
            maxt = t;
        }
        if (cnt < minn) {
            minn = cnt;
            mint = t;
        }
    }

    cout << maxt << '\n' << mint;

    return 0;
}

跳过分隔符。 遇到空格、逗号,i 往后走,连续多个也要跳过。

取出一个单词。 用 while 收集字符,碰到分隔符或行尾就停;i < len 写在访问 s[i] 前面。

更新最长、最短单词。 用 >、<,不加等号,并列时保留第一个。

截取子串

从字符串中取出一段,用 substr。

string s = "abcdef";
cout << s.substr(1, 2); // 从下标1开始,取2个字符,得到bc
string s = "abcdef";
cout << s.substr(1); // 从下标1开始,取到末尾,得到bcdef

substr 得到一个新字符串,不会改变原来的 s。起点不能超过 s.size()。

翻转字符串

把 abc 翻转成 cba,可以用 reverse,需要 <algorithm>。

string s = "abc";
reverse(s.begin(), s.end()); // s变成cba

查找后,逐个替换

查找子串、字符

string s = "zqoizq";
cout << s.find("zq");    // 第一次出现的位置,0
cout << s.find('q');     // 第一次出现的位置,1
cout << s.find("zq", 2); // 从下标2往后找,得到4

没找到,返回 string::npos。

if (s.find("abc") == string::npos) cout << "没找到";

不要把 find 的结果直接当条件:位置 0 也可能是找到,而 npos 也不是 0。

替换子串

string s = "abcdef";
s.replace(1, 2, "xxx"); // 从下标1开始,替换2个字符,得到axxxdef

逐个替换

把句子里的 cat 逐个替换成 dog。这里按字符查找,不判断单词边界。

string s = "cat cat";
auto p = s.find("cat");
while (p != string::npos) {
    s.replace(p, 3, "dog");
    p = s.find("cat", p + 3);
}

cout << s; // 输出dog dog

auto 自动确定 p 的类型,string::npos 表示没找到。

替换完,继续往后找。 dog 长度为 3,所以下次从 p + 3 开始。

别反复查找刚替换的位置;新内容包含原查找串时,可能停不下来。

统计单词(先不看)

统计单词出现次数,可以用 map,需要 <map>。学过 STL 后再看。

int n;
cin >> n;

map<string, int> mp;
string s;
while (n--) {
    cin >> s;
    mp[s]++;
}

for (auto p : mp) cout << p.first << ' ' << p.second << '\n';

mp[s] 记录单词 s 的次数,新单词从 0 开始计数。

first 是单词,second 是次数,按单词的字典序输出。