mirror of
https://github.com/Light-City/CPlusPlusThings.git
synced 2026-10-29 03:14:06 +08:00
- const README: rewrite the space-saving claim per issue #5 follow-ups (constant-expression const vs #define immediates; which const qualify as constant expressions) - const README: fix the class-section diagnosis per issue #338 (overload resolution picks the const overload; the restriction only surfaces once that overload is removed) - sizeof README: virtual-inheritance result is compiler-dependent (GCC merges vbptr+vfptr -> 16, MSVC keeps them separate -> 32) #246 - static README: new section on internal linkage / access restriction with anonymous-namespace comparison #142 - 10-day practice: full problem list table + fixed day links #136 - new design_pattern/singleton/singleton_default.hpp: reusable thread-safe CRTP singleton template, compile+concurrency tested #303
This commit is contained in:
98
site_extras/cpp-guides-cpp-string-split-methods.md
Normal file
98
site_extras/cpp-guides-cpp-string-split-methods.md
Normal file
@@ -0,0 +1,98 @@
|
||||
> 来自 [C++那些事网站](https://light-city.github.io/stories_things/cpp-guides/cpp-string-split-methods/) 的文章,由站点同步脚本导出。
|
||||
|
||||
# C++ 字符串六种分割方法
|
||||
|
||||
通常我们在开发的时候会对一个长字符串依据分隔符进行分割,从而得到我们想要的字符串,大家都说C++字符串分割并没有那么方便,今天来总结一下5种方法分割字符串。
|
||||
|
||||
包含了从C++11到C++20的写法,以及C风格。
|
||||
|
||||
为了方便后续文章的讲解,我们先定义一个函数原型:
|
||||
|
||||
- 参数:两个字符串,一个表示原字符串,另一个表示分隔符
|
||||
|
||||
- 返回值:字符串数组
|
||||
|
||||
注:懒人版,可以从星球获取完整代码。
|
||||
|
||||
## 1.find分割
|
||||
|
||||
第一种方法便是大家常用的先找到分割符的位置,然后划分字符串,添加到数组中,于是有了下面的代码。
|
||||
|
||||
```cpp
|
||||
nt start = 0;
|
||||
int end = s.find(delim);
|
||||
std::vector<std::string> result;
|
||||
while (end != std::string::npos) {
|
||||
result.push_back(s.substr(start, end - start));
|
||||
start = end + delim.size();
|
||||
end = s.find(delim, start);
|
||||
}
|
||||
|
||||
result.push_back(s.substr(start, end - start));
|
||||
```
|
||||
|
||||
这种办法是否还能进行优化呢?
|
||||
|
||||
答案是肯定的,为了使得代码看起来更加优雅,我们可以每次删除前面已经输出的子串,然后find逻辑一致。
|
||||
|
||||
```cpp
|
||||
while (end != std::string::npos) {
|
||||
result.push_back(s.substr(0, end));
|
||||
s.erase(0, end + delim.size());
|
||||
end = s.find(delim);
|
||||
}
|
||||
```
|
||||
|
||||
## 2.C++20 Ranges与Views分割
|
||||
|
||||
C++20中我们可以使用 `std::ranges::views::split()` 创建一个分隔符的视图,然后使用transform,将每个子视图转换为 `std::string`。
|
||||
|
||||
```cpp
|
||||
auto split_transform_view = s | std::ranges::views::split(delim) |
|
||||
std::ranges::views::transform([](auto&& str) {
|
||||
return std::string(str.begin(), str.end());
|
||||
});
|
||||
```
|
||||
|
||||
是不是很简单,可能一些人没看懂,诶关系去看之前的C++20文章吧。
|
||||
|
||||
## 3.正则分割
|
||||
|
||||
使用 `std::regex` 对象构造分隔符模式,使用`std::sregex_token_iterator` 遍历由正则表达式模式分隔的子字符串,-1表示提取不匹配的字符串,即除了分割符的字符串。
|
||||
|
||||
```cpp
|
||||
std::regex r(delim);
|
||||
return {std::sregex_token_iterator(s.begin(), s.end(), r, -1),
|
||||
std::sregex_token_iterator()};
|
||||
```
|
||||
|
||||
## 4.istringstream分割
|
||||
|
||||
getline每次只能传递一个分隔符,于是分隔之后,需要继续跳过后续的分隔符。
|
||||
|
||||
```cpp
|
||||
std::istringstream ss(s);
|
||||
while (std::getline(ss, token, *(it = delim.begin()))) {
|
||||
result.push_back(token);
|
||||
it++;
|
||||
|
||||
while (it != delim.end() && ss.peek() == *(it)) {
|
||||
it++;
|
||||
ss.get();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5.C风格的strtok分割
|
||||
|
||||
使用 `strtok()` 将字符串分割成标记,然后while循环依次提取即可。
|
||||
|
||||
```cpp
|
||||
token = strtok((char*)s.c_str(), delim.c_str());
|
||||
while (token != NULL) {
|
||||
result.push_back(token);
|
||||
token = strtok(NULL, delim.c_str());
|
||||
}
|
||||
```
|
||||
|
||||
以上便是常用的几种方法,你还有其他方法吗?欢迎留言区见,本节懒人版可以从星球获取完整代码。
|
||||
Reference in New Issue
Block a user