Разбор строки с разделителями-запятыми std :: string

Если у меня есть строка std ::, содержащая список чисел, разделенных запятыми, какой самый простой способ проанализировать числа и поместить их в целочисленный массив?

Я не хочу обобщать это на разовое разбирательство. Просто простая строка целых чисел, разделенных запятыми, таких как «1,1,1,1,2,1,1,1,0».

#include  #include  #include  #include  int main() { std::string str = "1,2,3,4,5,6"; std::vector 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 и берет что-либо, разделенное запятой.

 stringstream ss( "1,1,1,1, or something else ,1,1,1,0" ); vector result; while( ss.good() ) { string substr; getline( ss, substr, ',' ); result.push_back( substr ); } 

Еще один, довольно иной подход: используйте специальный язык, который обрабатывает запятые как пробел:

 #include  #include  struct csv_reader: std::ctype { csv_reader(): std::ctype(get_table()) {} static std::ctype_base::mask const* get_table() { static std::vector 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() stream с локалью, которая включает этот грань. Как только вы это сделаете, вы можете читать цифры, как будто запятые не были там вообще. Например, мы будем считывать номера с разделителями-запятыми из ввода и записывать затем одну строку на стандартный вывод:

 #include  #include  #include  int main() { std::cin.imbue(std::locale(std::locale(), new csv_reader())); std::copy(std::istream_iterator(std::cin), std::istream_iterator(), std::ostream_iterator(std::cout, "\n")); return 0; } 

Библиотека инструментов C ++ String Toolkit (Strtk) имеет следующее решение вашей проблемы:

 #include  #include  #include  #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_list; strtk::parse(int_string,",",int_list); std::string double_string = "123.456|789.012|345.678|901.234|567.890"; std::deque 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 ints; tokenizer<> tok(values); transform(tok.begin(), tok.end(), back_inserter(ints), ToInt()); 

Вы также можете использовать следующую функцию.

 void tokenize(const string& str, vector& 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 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  #include  #include  template 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; } 

Хорошие свойства:

  • Нет зависимостей (например, повышение)
  • Не безумный однострочный
  • Легко понять (надеюсь)
  • Отлично обрабатывает пространства
  • Не выделяет разбиения, если вы этого не хотите, например, вы можете обрабатывать их с помощью lambda, как показано.
  • Не добавляет персонажей по одному - должен быть быстрым.
  • Если вы используете C ++ 17, вы можете изменить его, чтобы использовать std::stringview а затем он не будет делать никаких распределений и должен быть очень быстрым.

Некоторые варианты дизайна, которые вы, возможно, пожелаете изменить:

  • Пустые записи не игнорируются.
  • Пустая строка вызовет f () один раз.

Примеры входов и выходов:

 "" -> {""} "," -> {"", ""} "1," -> {"1", ""} "1" -> {"1"} " " -> {" "} "1, 2," -> {"1", " 2", ""} " ,, " -> {" ", "", " "} 
 #include  #include  const char *input = "1,1,1,1,2,1,1,1,0"; int main() { std::stringstream ss(input); std::vector output; int i; while (ss >> i) { output.push_back(i); ss.ignore(1); } } 

Плохой ввод (например, последовательные разделители) испортит это, но вы сказали просто.

Я удивлен, что никто не предложил решение, использующее std::regex :

 #include  #include  #include  #include  void parse_csint( const std::string& str, std::vector& result ) { typedef std::regex_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]); } ); } 

Эта функция вставляет все целые числа в обратной последовательности входного вектора. Вы можете настроить регулярное выражение для включения отрицательных целых чисел или чисел с плавающей запятой и т. Д.

 string exp = "token1 token2 token3"; char delimiter = ' '; vector str; string acc = ""; for(int i = 0; i < exp.size(); i++) { if(exp[i] == delimiter) { str.push_back(acc); acc = ""; } else acc += exp[i]; } 

Я еще не могу прокомментировать (начало работы на сайте), но добавила более общую версию превосходного classа Джерри Коффина на свой пост.

Спасибо Джерри за супер идею.

(Потому что он должен быть проверен экспертами, добавив его здесь слишком временно)

 struct SeparatorReader: std::ctype { template SeparatorReader(const T &seps): std::ctype(get_table(seps), true) {} template std::ctype_base::mask const *get_table(const T &seps) { auto &&rc = new std::ctype_base::mask[std::ctype::table_size](); for(auto &&sep: seps) rc[static_cast(sep)] = std::ctype_base::space; return &rc[0]; } }; 
 bool GetList (const std::string& src, std::vector& res) { using boost::lexical_cast; using boost::bad_lexical_cast; bool success = true; typedef boost::tokenizer > tokenizer; boost::char_separator sepa(","); tokenizer tokens(src, sepa); for (tokenizer::iterator tok_iter = tokens.begin(); tok_iter != tokens.end(); ++tok_iter) { try { res.push_back(lexical_cast(*tok_iter)); } catch (bad_lexical_cast &) { success = false; } } return success; } 

простая конструкция, легко адаптируемая, простая поддержка.

 std::string stringIn = "my,csv,,is 10233478,separated,by commas"; std::vector commaSeparated(1); int commaCounter = 0; for (int i=0; i 

в конце вы будете иметь вектор строк с каждым элементом предложения, разделенным пробелами. пустые строки сохраняются как отдельные элементы.

Простая функция копирования / вставки, основанная на токенизаторе boost .

 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++; } 

Это самый простой способ, который я использовал много. Он работает для любого односимвольного разделителя.

 #include using namespace std; int main() { string str; cin >> str; int temp; vector 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< в #include using namespace std; int main() { string str; cin >> str; int temp; vector 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< 
 void ExplodeString( const std::string& string, const char separator, std::list& 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  #include  #include  #include  const char *input = ",,29870,1,abc,2,1,1,1,0"; int main() { std::stringstream ss(input); std::vector 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 (std::cout, " ") ); return 0; } 
  • Преобразование DateTime из строки C #
  • strcmp на строке, прочитанной с помощью fgets
  • Почему оператор switch не может применяться к строкам?
  • Как найти n-ое появление символа в строке?
  • Как проверить, являются ли два слова анаграммами
  • Как использовать java.String.format в Scala?
  • Как избежать строки в Java?
  • Создание оператора конкатенации строк в R
  • Метод обратного эффекта java String.split ()?
  • Что такое хорошая 64-битная hash-функция в Java для текстовых строк?
  • Преобразование std :: __ cxx11 :: string в std :: string
  • Давайте будем гением компьютера.