c++ - 在 C++ 中拆分字符串的最佳实践
问题描述
我正在为竞争性编程学习 C++。我最近遇到了一个需要将字符串拆分为向量的问题(我来自 Python 和 JavaScript 背景,所以有一个简单的内置函数负责拆分字符串)
C ++中有类似的东西吗?一种节省时间的简单方法。我会很感激你的意见
谢谢!
解决方案
很难回答。由于竞争性编程与 C++ 的真正意图没有太大关系。
反正。
将字符串拆分为标记是一项非常古老的任务。有许多可用的解决方案。都有不同的属性。有些难以理解,有些难以开发,有些更复杂,更慢或更快或更灵活或不灵活。
备择方案
- 手工制作,许多变体,使用指针或迭代器,可能难以开发且容易出错。
- 使用旧式
std::strtok
功能。也许不安全。也许不应该再使用了 std::getline
. 最常用的实现。但实际上是一种“误用”,并没有那么灵活- 使用专门为此目的开发的专用现代功能,最灵活且最适合 STL 环境和算法环境。但是比较慢。
请在一段代码中查看 4 个示例。
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <regex>
#include <algorithm>
#include <iterator>
#include <cstring>
#include <forward_list>
#include <deque>
using Container = std::vector<std::string>;
std::regex delimiter{ "," };
int main() {
// Some function to print the contents of an STL container
auto print = [](const auto& container) -> void { std::copy(container.begin(), container.end(),
std::ostream_iterator<std::decay<decltype(*container.begin())>::type>(std::cout, " ")); std::cout << '\n'; };
// Example 1: Handcrafted -------------------------------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};
// Search for comma, then take the part and add to the result
for (size_t i{ 0U }, startpos{ 0U }; i <= stringToSplit.size(); ++i) {
// So, if there is a comma or the end of the string
if ((stringToSplit[i] == ',') || (i == (stringToSplit.size()))) {
// Copy substring
c.push_back(stringToSplit.substr(startpos, i - startpos));
startpos = i + 1;
}
}
print(c);
}
// Example 2: Using very old strtok function ----------------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};
// Split string into parts in a simple for loop
#pragma warning(suppress : 4996)
for (char* token = std::strtok(const_cast<char*>(stringToSplit.data()), ","); token != nullptr; token = std::strtok(nullptr, ",")) {
c.push_back(token);
}
print(c);
}
// Example 3: Very often used std::getline with additional istringstream ------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};
// Put string in an std::istringstream
std::istringstream iss{ stringToSplit };
// Extract string parts in simple for loop
for (std::string part{}; std::getline(iss, part, ','); c.push_back(part))
;
print(c);
}
// Example 4: Most flexible iterator solution ------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
//
// Everything done already with range constructor. No additional code needed.
//
print(c);
// Works also with other containers in the same way
std::forward_list<std::string> c2(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
print(c2);
// And works with algorithms
std::deque<std::string> c3{};
std::copy(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {}, std::back_inserter(c3));
print(c3);
}
return 0;
}
推荐阅读
- javascript - 快递:空的req.body
- python-3.x - Azure ML 中的 FastText 和数据集与 Python
- python - 向 PYSCIPOPT 添加约束?
- arrays - Java:将字符串返回到 HashMap
- apache - 将所有非 www 重定向到 www,将所有 http 重定向到 https,并排除子域
- gradle - Gradle Gretty 插件的替代品
- c++ - 使用自动推导出的 lambda 参数作为常量表达式
- python - Openpyxl保存损坏的文件,android
- python - SQLAlchemy 和 pg8000 KeyError / Broken Pipe on Google App Engine with Postgresql
- javascript - 导入/导出 Javascript,动态创建按钮事件 onclick(ES6)