Java有一个方便的分割方法:
String str = "The quick brown fox";
String[] results = str.split(" ");
在c++中有简单的方法来做到这一点吗?
Java有一个方便的分割方法:
String str = "The quick brown fox";
String[] results = str.split(" ");
在c++中有简单的方法来做到这一点吗?
当前回答
/// split a string into multiple sub strings, based on a separator string
/// for example, if separator="::",
///
/// s = "abc" -> "abc"
///
/// s = "abc::def xy::st:" -> "abc", "def xy" and "st:",
///
/// s = "::abc::" -> "abc"
///
/// s = "::" -> NO sub strings found
///
/// s = "" -> NO sub strings found
///
/// then append the sub-strings to the end of the vector v.
///
/// the idea comes from the findUrls() function of "Accelerated C++", chapt7,
/// findurls.cpp
///
void split(const string& s, const string& sep, vector<string>& v)
{
typedef string::const_iterator iter;
iter b = s.begin(), e = s.end(), i;
iter sep_b = sep.begin(), sep_e = sep.end();
// search through s
while (b != e){
i = search(b, e, sep_b, sep_e);
// no more separator found
if (i == e){
// it's not an empty string
if (b != e)
v.push_back(string(b, e));
break;
}
else if (i == b){
// the separator is found and right at the beginning
// in this case, we need to move on and search for the
// next separator
b = i + sep.length();
}
else{
// found the separator
v.push_back(string(b, i));
b = i;
}
}
}
boost库很好,但并不总是可用的。手工做这些事情也是很好的脑力锻炼。这里我们只使用STL中的std::search()算法,参见上面的代码。
其他回答
对于简单的事情,我只使用以下方法:
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卡、摄像头)传入。除了在启动时读取外部配置文件以外,我从未将这个函数用于更复杂或时间要求更严格的事情。
我只是看了所有的答案,找不到下一个前提条件的解决方案:
没有动态内存分配 不使用boost 不使用正则表达式 c++17标准
这就是我的解
#include <iomanip>
#include <iostream>
#include <iterator>
#include <string_view>
#include <utility>
struct split_by_spaces
{
std::string_view text;
static constexpr char delim = ' ';
struct iterator
{
const std::string_view& text;
std::size_t cur_pos;
std::size_t end_pos;
std::string_view operator*() const
{
return { &text[cur_pos], end_pos - cur_pos };
}
bool operator==(const iterator& other) const
{
return cur_pos == other.cur_pos && end_pos == other.end_pos;
}
bool operator!=(const iterator& other) const
{
return !(*this == other);
}
iterator& operator++()
{
cur_pos = text.find_first_not_of(delim, end_pos);
if (cur_pos == std::string_view::npos)
{
cur_pos = text.size();
end_pos = cur_pos;
return *this;
}
end_pos = text.find(delim, cur_pos);
if (cur_pos == std::string_view::npos)
{
end_pos = text.size();
}
return *this;
}
};
[[nodiscard]] iterator begin() const
{
auto start = text.find_first_not_of(delim);
if (start == std::string_view::npos)
{
return iterator{ text, text.size(), text.size() };
}
auto end_word = text.find(delim, start);
if (end_word == std::string_view::npos)
{
end_word = text.size();
}
return iterator{ text, start, end_word };
}
[[nodiscard]] iterator end() const
{
return iterator{ text, text.size(), text.size() };
}
};
int main(int argc, char** argv)
{
using namespace std::literals;
auto str = " there should be no memory allocation during parsing"
" into words this line and you should'n create any"
" contaner for intermediate words "sv;
auto comma = "";
for (std::string_view word : split_by_spaces{ str })
{
std::cout << std::exchange(comma, ",") << std::quoted(word);
}
auto only_spaces = " "sv;
for (std::string_view word : split_by_spaces{ only_spaces })
{
std::cout << "you will not see this line in output" << std::endl;
}
}
这是一个非常简单的问题:
#include <vector>
#include <string>
using namespace std;
vector<string> split(const char *str, char c = ' ')
{
vector<string> result;
do
{
const char *begin = str;
while(*str != c && *str)
str++;
result.push_back(string(begin, str));
} while (0 != *str++);
return result;
}
c++标准库算法普遍基于迭代器,而不是具体的容器。不幸的是,这使得在c++标准库中很难提供类似java的split函数,尽管没有人认为这很方便。但是它的返回类型是什么呢?std::向量< std:: basic_string <…> >吗?也许吧,但这样我们就被迫执行(可能是冗余的和昂贵的)分配。
相反,c++提供了大量基于任意复杂的分隔符分割字符串的方法,但它们都没有像其他语言中那样封装得很好。各种各样的方法填满了整个博客文章。
在最简单的情况下,你可以使用std::string::find进行迭代,直到你击中std::string::npos,然后使用std::string::substr提取内容。
一个更流畅的(和惯用的,但基本的)版本在空格上拆分将使用std::istringstream:
auto iss = std::istringstream{"The quick brown fox"};
auto str = std::string{};
while (iss >> str) {
process(str);
}
使用std::istream_iterators,还可以使用vector的迭代器范围构造函数将string流的内容复制到vector中。
多个库(如Boost.Tokenizer)提供特定的标记器。
更高级的分裂需要正则表达式。c++特别为此提供了std::regex_token_iterator:
auto const str = "The quick brown fox"s;
auto const re = std::regex{R"(\s+)"};
auto const vec = std::vector<std::string>(
std::sregex_token_iterator{begin(str), end(str), re, -1},
std::sregex_token_iterator{}
);
我知道你想要一个c++的解决方案,但你可能会认为这是有帮助的:
Qt
#include <QString>
...
QString str = "The quick brown fox";
QStringList results = str.split(" ");
在这个例子中,与Boost相比的优势在于,它直接一对一地映射到你的文章代码。
详见Qt文档