在 C++ 中拆分字符串的最佳实践
Posted
技术标签:
【中文标题】在 C++ 中拆分字符串的最佳实践【英文标题】:Best Practice to split a string in C++ 【发布时间】:2020-05-19 00:08:59 【问题描述】:我正在学习 C++ 的竞争性编程。我最近遇到了一个需要将字符串拆分成向量的问题(我来自 Python 和 javascript 背景,所以有这个简单的内置函数负责拆分字符串)
C++ 中有类似的东西吗?一种节省时间的简单方法。非常感谢您的意见
谢谢!
【问题讨论】:
你在这里有一个规范的答案 -> ***.com/questions/236129/… 根据分隔符拆分字符串?您可以将字符串放入std::stringstream
并使用带有自定义分隔符的std::getline()
,将每个组件添加到向量中。
如果你在空格上分割然后std::copy(std::istream_iterator<std::string>(std::cin), std::istream_iterator<std::string>(), std::back_inserter(words));
见onlinegdb.com/H1mqg6lo8
我正在学习 C++ 的竞争性编程。 ... 一种节省时间的简单方法。 提示:你没有获得所需的通过巧妙的数据输入提高速度。您可以通过选择正确的算法来获得它,该算法的复杂性比天真的或蛮力方法要低得多。 (这是我在这里和那里读到的内容的印象。我必须承认我从未尝试过自己竞争性编程。)
这肯定很有见地。谢谢
【参考方案1】:
很难回答。由于竞争性编程与 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;
【讨论】:
以上是关于在 C++ 中拆分字符串的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章