如果我有一个包含逗号分隔数字的std::string,最简单的方法是什么来解析这些数字并将它们放入整数数组中?
我不想将其泛化到解析其他任何内容。只是一个简单的逗号分隔整数数字字符串,如"1,1,1,1,2,1,1,1,0"。
每次输入一个数字,并检查下一个字符是否为,
。如果是,则忽略它。
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
int main()
{
std::string str = "1,2,3,4,5,6";
std::vector<int> vect;
std::stringstream ss(str);
for (int i; ss >> i;) {
vect.push_back(i);
if (ss.peek() == ',')
ss.ignore();
}
for (std::size_t i = 0; i < vect.size(); i++)
std::cout << vect[i] << std::endl;
}
if (ss.peek() == ',' || ss.peek() == ' ')
,意思是如果ss
流的下一个字符是逗号或空格。 - safe_mallocsize_t i;
而不是int i;
会更好吗?因为vect.size()
返回的是size_t
变量类型。 - Volomikewhile (ss.peek() == ',' || ss.peek() == ' ')
,而不是原文中的内容。 - saurabheights更简洁,使用标准且适用于逗号分隔的任何内容。
stringstream ss( "1,1,1,1, or something else ,1,1,1,0" );
vector<string> result;
while( ss.good() )
{
string substr;
getline( ss, substr, ',' );
result.push_back( substr );
}
result.push_back("");
,这可能不是您想要的。 - Timmmm另一种截然不同的方法:使用将逗号视为空格的特殊语言环境:
#include <locale>
#include <vector>
struct csv_reader: std::ctype<char> {
csv_reader(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());
rc[','] = std::ctype_base::space;
rc['\n'] = std::ctype_base::space;
rc[' '] = std::ctype_base::space;
return &rc[0];
}
};
要使用此功能,您需要用包含此 facet 的 locale 对流进行 imbue()
。完成后,您可以像逗号不存在一样读取数字。为了举例说明,我们将从输入中读取逗号分隔的数字,并将它们一个接一个地写入标准输出:
#include <algorithm>
#include <iterator>
#include <iostream>
int main() {
std::cin.imbue(std::locale(std::locale(), new csv_reader()));
std::copy(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::ostream_iterator<int>(std::cout, "\n"));
return 0;
}
string tmp = "1,2,blab,blub";
int startTime2 = 0;
int endTime2 = 0;
string startDate2;
string endDate2;
stringstream ss( tmp );
ss.imbue( std::locale( std::locale(), new csv_reader() ) );
ss >> startTime2 >> endTime2 >> startDate2 >> endDate2;
- tmanthey1,2,3,,5,6,7
。 - Fabio A.C++字符串工具库(Strtk) 对你的问题有以下解决方案:
#include <string>
#include <deque>
#include <vector>
#include "strtk.hpp"
int main()
{
std::string int_string = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15";
std::vector<int> int_list;
strtk::parse(int_string,",",int_list);
std::string double_string = "123.456|789.012|345.678|901.234|567.890";
std::deque<double> double_list;
strtk::parse(double_string,"|",double_list);
return 0;
}
更多示例可以在这里找到
使用通用算法和Boost.Tokenizer的另一种解决方案:
struct ToInt
{
int operator()(string const &str) { return atoi(str.c_str()); }
};
string values = "1,2,3,4,5,9,8,7,6";
vector<int> ints;
tokenizer<> tok(values);
transform(tok.begin(), tok.end(), back_inserter(ints), ToInt());
这里有许多相当糟糕的回答,所以我会附上我的(包括测试程序):
#include <string>
#include <iostream>
#include <cstddef>
template<typename StringFunction>
void splitString(const std::string &str, char delimiter, StringFunction f) {
std::size_t from = 0;
for (std::size_t i = 0; i < str.size(); ++i) {
if (str[i] == delimiter) {
f(str, from, i);
from = i + 1;
}
}
if (from <= str.size())
f(str, from, str.size());
}
int main(int argc, char* argv[]) {
if (argc != 2)
return 1;
splitString(argv[1], ',', [](const std::string &s, std::size_t from, std::size_t to) {
std::cout << "`" << s.substr(from, to - from) << "`\n";
});
return 0;
}
优点:
std::stringview
,然后它将不会做任何分配,并且应该非常快。一些您可能希望更改的设计选择:
示例输入和输出:
"" -> {""}
"," -> {"", ""}
"1," -> {"1", ""}
"1" -> {"1"}
" " -> {" "}
"1, 2," -> {"1", " 2", ""}
" ,, " -> {" ", "", " "}
void tokenize(const string& str, vector<string>& tokens, const string& delimiters = ",")
{
// Skip delimiters at beginning.
string::size_type lastPos = str.find_first_not_of(delimiters, 0);
// Find first non-delimiter.
string::size_type pos = str.find_first_of(delimiters, lastPos);
while (string::npos != pos || string::npos != lastPos) {
// Found a token, add it to the vector.
tokens.push_back(str.substr(lastPos, pos - lastPos));
// Skip delimiters.
lastPos = str.find_first_not_of(delimiters, pos);
// Find next non-delimiter.
pos = str.find_first_of(delimiters, lastPos);
}
}
std::string input="1,1,1,1,2,1,1,1,0";
std::vector<long> output;
for(std::string::size_type p0=0,p1=input.find(',');
p1!=std::string::npos || p0!=std::string::npos;
(p0=(p1==std::string::npos)?p1:++p1),p1=input.find(',',p0) )
output.push_back( strtol(input.c_str()+p0,NULL,0) );
当然,在strtol()
中检查转换错误是一个好主意。也许这段代码还可以从其他错误检查中受益。
我很惊讶还没有人提出使用 std::regex
来解决问题:
#include <string>
#include <algorithm>
#include <vector>
#include <regex>
void parse_csint( const std::string& str, std::vector<int>& result ) {
typedef std::regex_iterator<std::string::const_iterator> re_iterator;
typedef re_iterator::value_type re_iterated;
std::regex re("(\\d+)");
re_iterator rit( str.begin(), str.end(), re );
re_iterator rend;
std::transform( rit, rend, std::back_inserter(result),
[]( const re_iterated& it ){ return std::stoi(it[1]); } );
}
std::string exp = "token1 token2 token3";
char delimiter = ' ';
std::vector<std::string> str;
std::string acc = "";
for(const auto &x : exp)
{
if(x == delimiter)
{
str.push_back(acc);
acc = "";
}
else
acc += x;
}
str.push_back(acc);