Разбор строки с разделителями-запятыми std :: string
Если у меня есть строка std ::, содержащая список чисел, разделенных запятыми, какой самый простой способ проанализировать числа и поместить их в целочисленный массив?
Я не хочу обобщать это на разовое разбирательство. Просто простая строка целых чисел, разделенных запятыми, таких как «1,1,1,1,2,1,1,1,0».
- Удалить все вхождения символа из строки
- Что такое «широкая строка символов» на языке C?
- Разделить строку строки фрейма данных на несколько столбцов
- Как получить двойные кавычки в строковый литерал?
- Почему byteArray имеет длину 22 вместо 20?
- Как проверить, являются ли два слова анаграммами
- Как избавиться от `устаревшего преобразования из строковой константы в 'char *' 'предупреждения в GCC?
- Ввод Java String Scanner не дожидается информации, перемещается непосредственно в следующий оператор. Как дождаться информации?
- Загрузите модуль node.js из строки в памяти
- Является строковым литералом в c ++, созданным в статической памяти?
- Как преобразовать String в InputStream в Java?
- Строка std :: содержит нулевой ограничитель?
- Быстрое удаление пунктуации с помощью панд
#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; }