C++字符串分割与替换
较难32字符串分割与替换:把文字拆开或换掉
你手上有一串用逗号分开的名字,比如“小明,小红,小刚”,想把它们一个个单独念出来;或者收到一句“我不喜欢吃菠菜”,想改成“我喜欢吃菠菜”。这些操作在编程里就叫字符串的分割和替换。想象一下:分割就像把一串珠子按颜色拆开,替换就像把项链上的某几颗珠子换成别的颜色。下面我们用C++来实现。
1. 字符串分割——自己动手拆字符串
C++标准库没有直接的 split 函数(像Python那样),但我们可以用 find 和 substr 自己造一个。这三样工具就像:
find:在一串文字里找到某个分隔符出现的位置(比如找到第一个逗号在第几个字符)substr:从某个位置切取一段文字- 循环:反复找,直到把整串拆完
生活中的例子:老师给了一个全班名单 "张三,李四,王五,赵六" 让你按学号念出来。你找到第一个逗号,把前面“张三”记下来,然后跳过分隔符,再找下一个逗号,以此类推。
下面这段代码演示了如何按逗号拆分字符串,并输出每个名字:
#include <iostream>
#include <string>
using namespace std;
int main() {
string data = "张三,李四,王五"; // 原始字符串
string delimiter = ","; // 分隔符
int start = 0; // 每次查找的起始位置
int end = data.find(delimiter); // 找到第一个分隔符的位置
while (end != string::npos) { // 只要还能找到分隔符
string token = data.substr(start, end - start); // 从start切到end前
cout << token << endl; // 输出当前名字
start = end + delimiter.length(); // 跳过分隔符本身
end = data.find(delimiter, start); // 从新起点继续找下一个
}
// 循环结束时,后面还有最后一段没有分隔符
string last = data.substr(start); // 取最后一段
cout << last << endl;
return 0;
}
输出结果:
张三
李四
王五
关键点解释:
string::npos是一个特殊值,表示“没找到”。如果find返回npos,说明后面没有分隔符了,循环结束。substr(start, length)的第二个参数是长度,end - start正好是这一段字符串的长度。- 每次找到分隔符后,
start要更新到分隔符后面的位置(end + delimiter.length()),否则会一直卡在同一个位置。
常见错误1:忘记更新 start 导致无限循环
新手容易犯这个错:在循环里忘了把 start 往前移,结果每次 find 都找到同一个逗号,程序就卡死了。
正确做法:每次处理完一段,一定要让 start 跳过刚才处理过的分隔符。
常见错误2:字符串末尾没有分隔符怎么办?
上面的循环已经处理了:循环结束后用 substr(start) 取出剩余部分。如果字符串最后正好有分隔符(比如 "张三,李四,"),那么最后一段就是空字符串 "",需要自己判断要不要忽略。根据实际情况来决定。
小技巧:把分割功能封装成函数
如果经常要拆分字符串,可以写成一个函数,返回一个 vector<string> 列表。下面是一个例子:
#include <vector>
// 按分隔符拆分字符串,返回各部分组成的vector
vector<string> split(string str, string delimiter) {
vector<string> pieces; // 存放拆分后的每一段
int start = 0;
int end = str.find(delimiter);
while (end != string::npos) {
pieces.push_back(str.substr(start, end - start)); // 把这一段加入列表
start = end + delimiter.length();
end = str.find(delimiter, start);
}
pieces.push_back(str.substr(start)); // 最后一段也加入
return pieces;
}
调用这个函数就能轻松得到所有片段,比如:
vector<string> names = split("苹果,香蕉,橘子", ",");
for (int i = 0; i < names.size(); i++) {
cout << names[i] << endl;
}
2. 字符串替换——把一部分文字换成另一部分
C++ 的 replace 方法可以替换字符串中指定位置的一段。但它只替换一次,不会自动替换所有出现的相同文字。要全部替换,需要自己写循环。
生活中的例子:你在作文里把“妈妈”写成了“妈妈妈”,现在想改成“妈妈”。或者你把聊天记录里的“哈哈”全部换成“嘿嘿”。
2.1 替换一处
最简单的用法:msg.replace(起始位置, 长度, 新字符串)。注意长度指的是要替换掉多少字符(而不是几个中文字)。
先看一个英文例子(一个字母占一个字节,长度容易算):
string msg = "I like apples.";
int pos = msg.find("apples"); // 找到“apples”的位置
if (pos != string::npos) { // 如果找到了
msg.replace(pos, 6, "oranges"); // 把从pos开始的6个字符换成"oranges"
}
cout << msg; // 输出 "I like oranges."
2.2 替换所有出现的地方
如果要替换所有“小猫”变成“小狗”,需要循环查找。注意每次替换后,查找起点要移动到替换内容的后面,否则可能陷入死循环。
string sentence = "我喜欢小猫。小猫很可爱。";
string target = "小猫";
string replacement = "小狗";
int pos = sentence.find(target);
while (pos != string::npos) {
sentence.replace(pos, target.length(), replacement); // 替换
pos = sentence.find(target, pos + replacement.length()); // 从替换后的位置后面再找
}
cout << sentence; // 输出 "我喜欢小狗。小狗很可爱。"
为什么 pos + replacement.length() 而不是 pos + 1?
如果替换的内容比原来长,或者短,新的查找起点必须跳过替换后的整个新串,否则可能再次匹配到刚替换进去的部分。例如把“aa”替换成“aaa”,如果不跳过,会一直停在原地无限循环。
关于中文的特别提醒
C++ 中 string 默认用 UTF-8 编码,一个汉字通常占 3 个字节(Windows下有些系统用GBK是2字节)。因此直接用 target.length() 会得到字节数,而不是汉字个数。比如 "小猫" 这个字符串,在UTF-8下 length() 可能返回6(每个汉字3字节)。为了安全,建议用英文字符练习,或者使用 wstring (宽字符) 处理中文。
为了简化,本文示例尽量用英文。 如果你确实需要替换中文,可以使用下面的方法(确保编译器支持UTF-8,并且文件保存为UTF-8编码):
string chinese = "我喜欢小猫。";
// 注意:字符串字面量前加 u8 表示UTF-8,但 length() 仍然返回字节数
// 比如 "小猫" 占6个字节
int pos = chinese.find("小猫");
if (pos != string::npos) {
chinese.replace(pos, 6, "小狗"); // 6是“小猫”的字节数,需要手动计算
}
更可靠的做法是使用 wstring 和 wcout,超出三级范围,这里不展开。
3. 完整示例:分割CSV并输出 + 替换单词
下面是一个完整的可运行程序,它先按逗号拆分 CSDN 风格的数据,再对其中某个单词进行替换(英文)。
#include <iostream>
#include <string>
using namespace std;
int main() {
// 第一部分:拆分
string csv = "apple,banana,orange,grape"; // 用逗号分隔的水果列表
string sep = ","; // 分隔符
int start = 0;
int end = csv.find(sep);
cout << "水果列表:" << endl;
while (end != string::npos) {
string fruit = csv.substr(start, end - start);
cout << fruit << endl;
start = end + sep.length();
end = csv.find(sep, start);
}
// 最后一个水果
cout << csv.substr(start) << endl;
cout << "--- 现在替换 'apple' 为 'orange' ---" << endl;
// 第二部分:替换所有 "apple" 为 "orange"
string sentence = "I have an apple. The apple is red.";
string target = "apple";
string replaceWith = "orange";
int pos = sentence.find(target);
while (pos != string::npos) {
sentence.replace(pos, target.length(), replaceWith);
pos = sentence.find(target, pos + replaceWith.length());
}
cout << sentence << endl; // 输出 "I have an orange. The orange is red."
return 0;
}
运行结果:
水果列表:
apple
banana
orange
grape
--- 现在替换 'apple' 为 'orange' ---
I have an orange. The orange is red.
4. 常见错误总结
| 错误 | 例子 | 正确做法 |
|---|---|---|
| 忘记更新 start 或 pos | while (...) { ... end = find(delimiter); } 没改 start | 每次处理后,把 start 移到分隔符后面 |
| 替换后查找起点不对 | pos = sentence.find(target, pos + 1); 可能跳过 | pos = sentence.find(target, pos + replacement.length()); |
| 中文长度按字节数 | 用 "小猫".length() 得到6,替换时用了2 | 手动计算字节数,或使用宽字符 |
混淆 npos 和 -1 | if (end == -1) 有时也可以,但建议用 string::npos | 始终用 string::npos |
5. 相关知识点指引
- 字符串查找:
find、rfind、find_first_of等——帮助你定位子串或字符。 - 字符串拼接:可以用
+或append把多个字符串连在一起。 vector容器:存多个拆分结果的利器,配合push_back使用。getline按行分割:从流中读取一行,也可以自定义分隔符(比如getline(ss, token, ','))。- 更高级的字符串处理:正则表达式(
<regex>库)能一次完成复杂的分割和替换。
掌握了这些,你就能像处理一串珠子一样,灵活地拆分和改造文字信息了!试着用学到的知识处理一下班级名单、购物清单或聊天记录吧。
例题精讲
使用C++的std::string::find函数分割字符串时,假设字符串s为"apple,banana,grape",分隔符为","。以下代码片段中,能够正确将所有子串存入vector中的是?
C++中,string::replace函数可以替换字符串中的指定部分。若string str = "Hello World!",执行str.replace(6, 5, "C++")后,str的值是?
使用find和substr实现分割时,如果字符串中包含连续的分隔符(例如"a,,b"),且我们希望将连续分隔符之间的空字符串也作为一个子串保留,则需要在每次找到分隔符后,从当前分隔符位置+1继续查找,并在循环结束后添加最后一个子串。
以下函数将字符串s按分隔符delim拆分为多个子串并返回vector。请补充完整代码。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> split(const string& s, char delim) {
vector<string> result;
string cur;
for (char ch : s) {
if (ch == delim) {
result.push_back(cur);
cur = ___;
} else {
cur += ch;
}
}
result.push_back(cur);
return result;
}以下函数实现将字符串str中的所有子串oldStr替换为newStr,并返回新字符串。请补充完整代码。
#include <iostream>
#include <string>
using namespace std;
string replaceAll(const string& str, const string& oldStr, const string& newStr) {
string result = str;
size_t pos = 0;
while ((pos = result.find(oldStr, pos)) != string::npos) {
result.replace(pos, oldStr.length(), newStr);
pos += ___;
}
return result;
}