如果我有一个包含以逗号分隔的数字列表的 std: : string,那么解析出这些数字并将它们放入整数数组的最简单方法是什么?
我不想把这个问题归纳为解析其他问题。只是一个简单的逗号分隔的整数字符串,比如“1,1,1,1,2,1,1,0”。
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) ); } }
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()中的转换错误。也许代码也可以从其他错误检查中获益。
strtol()
一次输入一个数字,并检查下面的字符是否为 ,。如果是,则丢弃它。
,
#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; }
#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); } }
错误的输入(例如连续的分隔符)会把这一点搞砸,但是您确实说了简单。
使用通用算法和 助推器,托克尼发射器的替代解决方案:
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());
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; }
还有另外一种相当不同的方法: 使用一种特殊的区域设置,将逗号作为空白:
#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()流。一旦你这样做了,你就可以阅读数字,就好像根本没有逗号一样。例如,我们将从输入中读取逗号分隔的数字,然后在标准输出中每行写出一个:
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; }
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; }
更多的例子可以找到 给你
#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; }
不那么冗长的,标准的,用逗号分开的。
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 ); }
您还可以使用以下函数。
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); } }
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]; }
结构简单,适应性强,维护方便。
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++; }
我还不能发表评论(从网站开始) ,但是在他的文章中添加了 Jerry Coffin 的奇妙的 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]; } };
我很惊讶还没有人提出使用 std::regex的解决方案:
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]); } ); }
此函数将所有整数插入到输入向量的后面。您可以调整正则表达式以包含负整数或浮点数等。
这里有很多非常糟糕的答案,所以我要加上我的(包括测试程序) :
#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", ""} " ,, " -> {" ", "", " "}
这是最简单的方法,我用了很多次。它适用于任何一个字符的分隔符。
#include<bits/stdc++.h> using namespace std; int main() { string str; cin >> str; int temp; vector<int> result; char ch; stringstream ss(str); do { ss>>temp; result.push_back(temp); }while(ss>>ch); for(int i=0 ; i < result.size() ; i++) cout<<result[i]<<endl; return 0; }