解析逗号分隔的std :: string
如果我有一个包含逗号分隔数字列表的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); int i; while (ss >> i) { vect.push_back(i); if (ss.peek() == ',') ss.ignore(); } for (i=0; i< vect.size(); i++) std::cout << vect.at(i)<<std::endl; }
还有一个相当不同的方法:使用一个特殊的区域,把逗号当作空白区域:
#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]; } };
为了使用这个,你用一个包含这个方面的语言环境插入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; }
不太详细,std和用逗号隔开的任何东西。
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 ); }
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());
您也可以使用以下功能。
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()
检查转换错误是一个好主意。 也许代码也可能受益于其他一些错误检查。
#include <sstream> #include <vector> const char *input = "1,1,1,1,2,1,1,1,0"; int main() { std::stringstream ss(input); std::vector<int> output; int i; while (ss >> i) { output.push_back(i); ss.ignore(1); } }
不好的输入(例如连续的分隔符)会搞砸了,但你确实说得简单。
我还不能评论(在网站上开始),但添加了更通用的版本杰里棺材的奇妙ctype的派生类到他的职位。
谢谢杰里的超级想法。
(因为它必须经过同行评审,所以在这里暂时添加)
struct SeparatorReader: std::ctype<char> { template<typename T> SeparatorReader(const T &seps): std::ctype<char>(get_table(seps), true) {} template<typename T> std::ctype_base::mask const *get_table(const T &seps) { auto &&rc = new std::ctype_base::mask[std::ctype<char>::table_size](); for(auto &&sep: seps) rc[static_cast<unsigned char>(sep)] = std::ctype_base::space; return &rc[0]; } };
string exp = "token1 token2 token3"; char delimiter = ' '; vector<string> str; string acc = ""; for(int i = 0; i < exp.size(); i++) { if(exp[i] == delimiter) { str.push_back(acc); acc = ""; } else acc += exp[i]; }
bool GetList (const std::string& src, std::vector<int>& res) { using boost::lexical_cast; using boost::bad_lexical_cast; bool success = true; typedef boost::tokenizer<boost::char_separator<char> > tokenizer; boost::char_separator<char> sepa(","); tokenizer tokens(src, sepa); for (tokenizer::iterator tok_iter = tokens.begin(); tok_iter != tokens.end(); ++tok_iter) { try { res.push_back(lexical_cast<int>(*tok_iter)); } catch (bad_lexical_cast &) { success = false; } } return success; }
结构简单,适应性强,维修方便。
std::string stringIn = "my,csv,,is 10233478,separated,by commas"; std::vector<std::string> commaSeparated(1); int commaCounter = 0; for (int i=0; i<stringIn.size(); i++) { if (stringIn[i] == ",") { commaSeparated.push_back(""); commaCounter++; } else { commaSeparated.at(commaCounter) += stringIn[i]; } }
最后你会得到一个由空格分隔的句子中的每个元素的字符串向量。 空字符串被保存为单独的项目。
简单的复制/粘贴功能,基于升压标记器 。
void strToIntArray(std::string string, int* array, int array_len) { boost::tokenizer<> tok(string); int i = 0; for(boost::tokenizer<>::iterator beg=tok.begin(); beg!=tok.end();++beg){ if(i < array_len) array[i] = atoi(beg->c_str()); i++; }
我很惊讶没有人提出了使用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]); } ); }
该函数将所有整数插入输入向量的后面。 您可以调整正则表达式以包含负整数或浮点数等
void ExplodeString( const std::string& string, const char separator, std::list<int>& result ) { if( string.size() ) { std::string::const_iterator last = string.begin(); for( std::string::const_iterator i=string.begin(); i!=string.end(); ++i ) { if( *i == separator ) { const std::string str(last,i); int id = atoi(str.c_str()); result.push_back(id); last = i; ++ last; } } if( last != string.end() ) result.push_back( atoi(&*last) ); } }
#include <sstream> #include <vector> #include <algorithm> #include <iterator> const char *input = ",,29870,1,abc,2,1,1,1,0"; int main() { std::stringstream ss(input); std::vector<int> output; int i; while ( !ss.eof() ) { int c = ss.peek() ; if ( c < '0' || c > '9' ) { ss.ignore(1); continue; } if (ss >> i) { output.push_back(i); } } std::copy(output.begin(), output.end(), std::ostream_iterator<int> (std::cout, " ") ); return 0; }