Java有一个方便的split方法:
String str = "The quick brown fox";
String[] results = str.split(" ");
C++中是否有简便的方法来做到这一点?
Java有一个方便的split方法:
String str = "The quick brown fox";
String[] results = str.split(" ");
C++中是否有简便的方法来做到这一点?
#include <iostream>
#include <string>
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>
using namespace std;
using namespace boost;
int main(int, char**)
{
string text = "token, test string";
char_separator<char> sep(", ");
tokenizer< char_separator<char> > tokens(text, sep);
BOOST_FOREACH (const string& t, tokens) {
cout << t << "." << endl;
}
}
更新至 C++11:
#include <iostream>
#include <string>
#include <boost/tokenizer.hpp>
using namespace std;
using namespace boost;
int main(int, char**)
{
string text = "token, test string";
char_separator<char> sep(", ");
tokenizer<char_separator<char>> tokens(text, sep);
for (const auto& t : tokens) {
cout << t << "." << endl;
}
}
char_separator
构造函数的第三个参数(drop_empty_tokens
是默认选项,另一个选项是keep_empty_tokens
)。 - Benoit#include <vector>
#include <string>
vector<string> split(const char *str, char c = ' ')
{
std::vector<std::string> result;
do
{
const char *begin = str;
while(*str != c && *str)
str++;
result.push_back(std::string(begin, str));
} while (0 != *str++);
return result;
}
["","a"]
。 - undefinedsplit
函数变得困难,尽管没有人会认为这很方便。但它的返回类型会是什么?std::vector<std::basic_string<…>>
吗?也许是,但那样我们就被迫执行(可能是冗余和昂贵的)分配。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_iterator
s,可以利用其迭代器范围构造函数将字符串流的内容复制到向量中。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{}
);
getline
。类似这样:std::istringstream iss(str);
std::string s;
while (std::getline(iss, s, ' ')) {
std::cout << s << std::endl;
}
split()
方法,返回一个std::vector<string>
,这非常有用。使用strtok进行分词。在我看来,除非strtok无法满足您的需求,否则没有必要围绕分词构建一个类。可能不行,但是在我15多年的C和C++解析代码编写经验中,我始终使用strtok。这里是一个例子。
char myString[] = "The quick brown fox";
char *p = strtok(myString, " ");
while (p) {
printf ("Token: %s\n", p);
p = strtok(NULL, " ");
}
以下是一些注意事项(可能不适合您的需求)。在此过程中,字符串将被“破坏”,这意味着 EOS 字符将放置在定界符位置。正确使用可能需要您制作一个非 const 版本的字符串。您还可以在解析过程中更改定界符列表。
在我自己的看法中,上面的代码比编写一个单独的类要简单得多,更易于使用。对我来说,这是语言提供的那些功能之一,并且它执行得很好,很干净。它只是一个“基于 C”的解决方案。它是合适的、容易的,而且您无需编写大量额外的代码:-)
您可以直接使用流、迭代器和复制算法来实现这一点。
#include <string>
#include <vector>
#include <iostream>
#include <istream>
#include <ostream>
#include <iterator>
#include <sstream>
#include <algorithm>
int main()
{
std::string str = "The quick brown fox";
// construct a stream from the string
std::stringstream strstr(str);
// use stream iterators to copy the stream to the vector as whitespace separated strings
std::istream_iterator<std::string> it(strstr);
std::istream_iterator<std::string> end;
std::vector<std::string> results(it, end);
// send the vector to stdout.
std::ostream_iterator<std::string> oit(std::cout);
std::copy(results.begin(), results.end(), oit);
}
std
保持原样,这样我就知道我的对象来自哪里,那只是一种风格问题。 - Matthieu M.使用regex_token_iterator
的解决方案:
#include <iostream>
#include <regex>
#include <string>
using namespace std;
int main()
{
string str("The quick brown fox");
regex reg("\\s+");
sregex_token_iterator iter(str.begin(), str.end(), reg, -1);
sregex_token_iterator end;
vector<string> vec(iter, end);
for (auto a : vec)
{
cout << a << endl;
}
}
不冒犯大家,但对于这么简单的问题,你们把事情搞得太复杂了。使用Boost有很多原因。但对于这么简单的问题,就像用20#的大锤打苍蝇。
void
split( vector<string> & theStringVector, /* Altered/returned value */
const string & theString,
const string & theDelimiter)
{
UASSERT( theDelimiter.size(), >, 0); // My own ASSERT macro.
size_t start = 0, end = 0;
while ( end != string::npos)
{
end = theString.find( theDelimiter, start);
// If at end, use length=maxLength. Else use length=end-start.
theStringVector.push_back( theString.substr( start,
(end == string::npos) ? string::npos : end - start));
// If at end, use start=maxSize. Else use start=end+delimiter.
start = ( ( end > (string::npos - theDelimiter.size()) )
? string::npos : end + theDelimiter.size());
}
}
#define SHOW(I,X) cout << "[" << (I) << "]\t " # X " = \"" << (X) << "\"" << endl
int
main()
{
vector<string> v;
split( v, "A:PEP:909:Inventory Item", ":" );
for (unsigned int i = 0; i < v.size(); i++)
SHOW( i, v[i] );
}
std::string
类没有包含一个 split() 函数? - Mr. Shickadancestart = ((end > (theString.size() - theDelimiter.size())) ? string::npos : end + theDelimiter.size());
,而while循环应该是while (start != string::npos)
。此外,在将子字符串插入向量之前,我会检查它是否为空。 - John KBoost库提供了一个 powerful 的 split 函数:boost::algorithm::split。
示例程序:
#include <vector>
#include <boost/algorithm/string.hpp>
int main() {
auto s = "a,b, c ,,e,f,";
std::vector<std::string> fields;
boost::split(fields, s, boost::is_any_of(","));
for (const auto& field : fields)
std::cout << "\"" << field << "\"\n";
return 0;
}
输出:
"a"
"b"
" c "
""
"e"
"f"
""
这是一个只使用STL(大约5行代码)的简单解决方案,使用std::find
和std::find_first_not_of
处理分隔符的重复(例如空格或句号),以及前导和尾随分隔符:
#include <string>
#include <vector>
void tokenize(std::string str, std::vector<string> &token_v){
size_t start = str.find_first_not_of(DELIMITER), end=start;
while (start != std::string::npos){
// Find next occurence of delimiter
end = str.find(DELIMITER, start);
// Push back the token found into vector
token_v.push_back(str.substr(start, end-start));
// Skip all occurences of the delimiter to find new start
start = str.find_first_not_of(DELIMITER, end);
}
}
试一试在线演示!
a,b,c,,,f,g
返回向量的5个成员a b c f g,而不包括空字符串。索引内容受到影响。:(在NMEA GPS句子等内容中,具有多个空字段的索引字符分隔字符串数据非常常见。 - guitarpicva