Java有一个方便的分割方法:
String str = "The quick brown fox";
String[] results = str.split(" ");
在c++中有简单的方法来做到这一点吗?
Java有一个方便的分割方法:
String str = "The quick brown fox";
String[] results = str.split(" ");
在c++中有简单的方法来做到这一点吗?
当前回答
Boost::tokenizer是您的好朋友,但是请考虑使用wstring/wchar_t而不是传统的string/char类型,使您的代码在国际化(i18n)问题上具有可移植性。
#include <iostream>
#include <boost/tokenizer.hpp>
#include <string>
using namespace std;
using namespace boost;
typedef tokenizer<char_separator<wchar_t>,
wstring::const_iterator, wstring> Tok;
int main()
{
wstring s;
while (getline(wcin, s)) {
char_separator<wchar_t> sep(L" "); // list of separator characters
Tok tok(s, sep);
for (Tok::iterator beg = tok.begin(); beg != tok.end(); ++beg) {
wcout << *beg << L"\t"; // output (or store in vector)
}
wcout << L"\n";
}
return 0;
}
其他回答
pystring是一个小型库,实现了Python的一系列字符串函数,包括split方法:
#include <string>
#include <vector>
#include "pystring.h"
std::vector<std::string> chunks;
pystring::split("this string", chunks);
// also can specify a separator
pystring::split("this-string", chunks, "-");
对于简单的事情,我只使用以下方法:
unsigned TokenizeString(const std::string& i_source,
const std::string& i_seperators,
bool i_discard_empty_tokens,
std::vector<std::string>& o_tokens)
{
unsigned prev_pos = 0;
unsigned pos = 0;
unsigned number_of_tokens = 0;
o_tokens.clear();
pos = i_source.find_first_of(i_seperators, pos);
while (pos != std::string::npos)
{
std::string token = i_source.substr(prev_pos, pos - prev_pos);
if (!i_discard_empty_tokens || token != "")
{
o_tokens.push_back(i_source.substr(prev_pos, pos - prev_pos));
number_of_tokens++;
}
pos++;
prev_pos = pos;
pos = i_source.find_first_of(i_seperators, pos);
}
if (prev_pos < i_source.length())
{
o_tokens.push_back(i_source.substr(prev_pos));
number_of_tokens++;
}
return number_of_tokens;
}
懦弱的免责声明:我编写实时数据处理软件,其中数据通过二进制文件、套接字或一些API调用(I/O卡、摄像头)传入。除了在启动时读取外部配置文件以外,我从未将这个函数用于更复杂或时间要求更严格的事情。
MFC/ATL有一个非常好的标记器。从MSDN:
CAtlString str( "%First Second#Third" );
CAtlString resToken;
int curPos= 0;
resToken= str.Tokenize("% #",curPos);
while (resToken != "")
{
printf("Resulting token: %s\n", resToken);
resToken= str.Tokenize("% #",curPos);
};
Output
Resulting Token: First
Resulting Token: Second
Resulting Token: Third
我知道这个问题已经有了答案,但我想有所贡献。也许我的解决方案有点简单,但这就是我想到的:
vector<string> get_words(string const& text, string const& separator)
{
vector<string> result;
string tmp = text;
size_t first_pos = 0;
size_t second_pos = tmp.find(separator);
while (second_pos != string::npos)
{
if (first_pos != second_pos)
{
string word = tmp.substr(first_pos, second_pos - first_pos);
result.push_back(word);
}
tmp = tmp.substr(second_pos + separator.length());
second_pos = tmp.find(separator);
}
result.push_back(tmp);
return result;
}
如果在我的代码中有更好的方法,或者有什么错误,请评论。
更新:添加通用分隔符
如果你正在使用c++ ranges——完整的range -v3库,而不是c++ 20所接受的有限功能——你可以这样做:
auto results = str | ranges::views::tokenize(" ",1);
... 这是惰性求值。你也可以在这个范围内设置一个向量:
auto results = str | ranges::views::tokenize(" ",1) | ranges::to<std::vector>();
如果str有n个字符组成m个单词,这将占用O(m)个空间和O(n)个时间。
参见标准库自己的标记化示例。