Split and convert from string to char array - c++

How to convert:
string x = "1+2+3";
to:
char y[] = {'1', '2', '3'};
What approach should I do?

The task is to split a string separated by '+'. In the below example, the delimiter ',' is used.
Splitting a string into tokens is a very old task. There are many many solutions available. All have different properties. Some are difficult to understand, some are hard to develop, some are more complex, slower or faster or more flexible or not.
Alternatives
Handcrafted, many variants, using pointers or iterators, maybe hard to develop and error prone.
Using old style std::strtok function. Maybe unsafe. Maybe should not be used any longer
std::getline. Most used implementation. But actually a "misuse" and not so flexible
Using dedicated modern function, specifically developed for this purpose, most flexible and good fitting into the STL environment and algortithm landscape. But slower.
Please see 4 examples in one piece of code.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <regex>
#include <algorithm>
#include <iterator>
#include <cstring>
#include <forward_list>
#include <deque>
using Container = std::vector<std::string>;
std::regex delimiter{ "," };
int main() {
// Some function to print the contents of an STL container
auto print = [](const auto& container) -> void { std::copy(container.begin(), container.end(),
std::ostream_iterator<std::decay<decltype(*container.begin())>::type>(std::cout, " ")); std::cout << '\n'; };
// Example 1: Handcrafted -------------------------------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};
// Search for comma, then take the part and add to the result
for (size_t i{ 0U }, startpos{ 0U }; i <= stringToSplit.size(); ++i) {
// So, if there is a comma or the end of the string
if ((stringToSplit[i] == ',') || (i == (stringToSplit.size()))) {
// Copy substring
c.push_back(stringToSplit.substr(startpos, i - startpos));
startpos = i + 1;
}
}
print(c);
}
// Example 2: Using very old strtok function ----------------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};
// Split string into parts in a simple for loop
#pragma warning(suppress : 4996)
for (char* token = std::strtok(const_cast<char*>(stringToSplit.data()), ","); token != nullptr; token = std::strtok(nullptr, ",")) {
c.push_back(token);
}
print(c);
}
// Example 3: Very often used std::getline with additional istringstream ------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};
// Put string in an std::istringstream
std::istringstream iss{ stringToSplit };
// Extract string parts in simple for loop
for (std::string part{}; std::getline(iss, part, ','); c.push_back(part))
;
print(c);
}
// Example 4: Most flexible iterator solution ------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
//
// Everything done already with range constructor. No additional code needed.
//
print(c);
// Works also with other containers in the same way
std::forward_list<std::string> c2(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
print(c2);
// And works with algorithms
std::deque<std::string> c3{};
std::copy(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {}, std::back_inserter(c3));
print(c3);
}
return 0;
}

You can use an std::vector<std::string> instead of char[], that way, it would work with more than one-digit numbers. Try this:
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
int main() {
using namespace std;
std::string str("1+2+3");
std::string buff;
std::stringstream ss(str);
std::vector<std::string> result;
while(getline(ss, buff, '+')){
result.push_back(buff);
}
for(std::string num : result){
std::cout << num << std::endl;
}
}
Here is a coliru link to show it works with numbers having more than one digit.

Here are my steps:
convert the original string into char*
split the obtained char* with the delimiter + by using the function strtok. I store each token into a vector<char>
convert this vector<char> into a C char array char*
#include <iostream>
#include <string.h>
#include <vector>
using namespace std;
int main()
{
string line = "1+2+3";
std::vector<char> vectChar;
// convert the original string into a char array to allow splitting
char* input= (char*) malloc(sizeof(char)*line.size());
strcpy(input,line.data());
// splitting the string
char *token = strtok(input, "+");
int len=0;
while(token) {
std::cout << *token;
vectChar.push_back(*token);
token = strtok(NULL, "+");
}
// end of splitting step
std::cout << std::endl;
//test display the content of the vect<char>={'1', '2', ...}
for (int i=0; i< vectChar.size(); i++)
{
std::cout << vectChar[i];
}
// Now that the vector contains the needed list of char
// we need to convert it to char array (char*)
// first malloc
char* buffer = (char*) malloc(vectChar.size()*sizeof(char));
// then convert the vector into char*
std::copy(vectChar.begin(), vectChar.end(), buffer);
std::cout << std::endl;
//now buffer={'1', '2', ...}
// les ut stest by displaying
while ( *buffer != '\0')
{
printf("%c", *buffer);
buffer++;
}
}

You can run/check this code in https://repl.it/#JomaCorpFX/StringSplit#main.cpp
Code
#include <iostream>
#include <vector>
std::vector<std::string> Split(const std::string &data, const std::string &toFind)
{
std::vector<std::string> v;
if (data.empty() || toFind.empty())
{
v.push_back(data);
return v;
}
size_t ini = 0;
size_t pos;
while ((pos = data.find(toFind, ini)) != std::string::npos)
{
std::string s = data.substr(ini, pos - ini);
if (!s.empty())
{
v.push_back(s);
}
ini = pos + toFind.length();
}
if (ini < data.length())
{
v.push_back(data.substr(ini));
}
return v;
}
int main()
{
std::string x = "1+2+3";
for (auto value : Split(x, u8"+"))
{
std::cout << "Value: " << value << std::endl;
}
std::cout << u8"Press enter to continue... ";
std::cin.get();
return EXIT_SUCCESS;
}
Output
Value: 1
Value: 2
Value: 3
Press enter to continue...

Related

How to convert an input string into an array in C++? [duplicate]

This question already has answers here:
C++ function split string into words
(1 answer)
taking input of a string word by word
(3 answers)
Right way to split an std::string into a vector<string>
(12 answers)
Closed last year.
myStr = input("Enter something - ")
// say I enter "Hi there"
arrayStr = myStr.split()
print(arrayStr)
// Output: ['Hi', 'there']
What is the exact C++ equivalent of this code? (My aim is to further iterate over the array and perform comparisons with other arrays).
One way of doing this would be using std::vector and std::istringstream as shown below:
#include <iostream>
#include <string>
#include<sstream>
#include <vector>
int main()
{
std::string input, temp;
//take input from user
std::getline(std::cin, input);
//create a vector that will hold the individual words
std::vector<std::string> vectorOfString;
std::istringstream ss(input);
//go word by word
while(ss >> temp)
{
vectorOfString.emplace_back(temp);
}
//iterate over all elements of the vector and print them out
for(const std::string& element: vectorOfString)
{
std::cout<<element<<std::endl;
}
return 0;
}
You can use string_views to avoid generating copies of the input string (efficient in memory), it literally will give you views on the words in the string, like this :
#include <iostream>
#include <string_view>
#include <vector>
inline bool is_delimiter(const char c)
{
// order by frequency in your input for optimal performance
return (c == ' ') || (c == ',') || (c == '.') || (c == '\n') || (c == '!') || (c == '?');
}
auto split_view(const char* line)
{
const char* word_start_pos = line;
const char* p = line;
std::size_t letter_count{ 0 };
std::vector<std::string_view> words;
// while parsing hasn't seen the terminating 0
while(*p != '\0')
{
// if it is a character from a word then start counting the letters in the word
if (!is_delimiter(*p))
{
letter_count++;
}
else
{
//delimiter reached and word detected
if (letter_count > 0)
{
//add another string view to the characters in the input string
// this will call the constructor of string_view with arguments const char* and size
words.emplace_back(word_start_pos, letter_count);
// skip to the next word
word_start_pos += letter_count;
}
// skip delimiters for as long as you encounter them
word_start_pos++;
letter_count = 0ul;
}
// move on to the next character
++p;
}
return words;
}
int main()
{
auto words = split_view("the quick brown fox is fast. And the lazy dog is asleep!");
for (const auto& word : words)
{
std::cout << word << "\n";
}
return 0;
}
#include <string>
#include <sstream>
#include <vector>
#include <iterator>
template <typename Out>
void split(const std::string &s, char delim, Out result) {
std::istringstream iss(s);
std::string item;
while (std::getline(iss, item, delim)) {
*result++ = item;
}
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
split(s, delim, std::back_inserter(elems));
return elems;
}
std::vector<std::string> x = split("one:two::three", ':');
Where 'x' is your converted array with 4 elements.
Basically #AnoopRana's solution but using STL algorithms and removing punctuation signs from words:
[Demo]
#include <cctype> // ispunct
#include <algorithm> // copy, transform
#include <iostream> // cout
#include <iterator> // istream_iterator, ostream_iterator
#include <sstream> // istringstream
#include <string>
#include <vector>
int main() {
const std::string s{"In the beginning, there was simply the event and its consequences."};
std::vector<std::string> ws{};
std::istringstream iss{s};
std::transform(std::istream_iterator<std::string>{iss}, {},
std::back_inserter(ws), [](std::string w) {
w.erase(std::remove_if(std::begin(w), std::end(w),
[](unsigned char c) { return std::ispunct(c); }),
std::end(w));
return w;
});
std::copy(std::cbegin(ws), std::cend(ws), std::ostream_iterator<std::string>{std::cout, "\n"});
}
// Outputs:
//
// In
// the
// beginning
// there
// was
// simply
// the
// event
// and
// its
// consequences

Finding item in string and say WHEN it was found - c++

I have a string of items (see code). I want to say when a specific item from that list is found. In my example I want the output to be 3 since the item is found after the first two items. I can print out the separate items to the console but I cannot figure out how to do a count on these two items. I think it is because of the while loop... I always get numbers like 11 instead of two separate 1s. Any tips? :)
#include <iostream>
#include <string>
using namespace std;
int main() {
string items = "box,cat,dog,cat";
string delim = ",";
size_t pos = 0;
string token;
string item1 = "dog";
int count = 0;
`;
while ((pos = items.find(delim)) != string::npos)
{
token = items.substr(0, pos);
if (token != item1)
{
cout << token << endl; //here I would like to increment count for every
//item before item1 (dog) is found
items.erase(0, pos + 1);
}
else if (token == item1)
return 0;
}
return 0; //output: box cat
}
I replaced your search algorithm with the method explode, that separates your string by a delimiter and returns a vector, which is better suited for searching and getting the element count:
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>
std::vector<std::string> explode(const std::string& s, char delim)
{
std::vector<std::string> result;
std::istringstream iss(s);
for (std::string token; std::getline(iss, token, delim); )
{
result.push_back(std::move(token));
}
return result;
}
int main()
{
std::string items = "box,cat,dog,cat";
std::string item1 = "dog";
char delim = ',';
auto resultVec = explode(items, delim);
auto itResult = std::find_if(resultVec.begin(), resultVec.end()
, [&item1](const auto& resultString)
{
return item1 == resultString;
});
if (itResult != resultVec.end())
{
auto index(std::distance(resultVec.begin(), itResult) + 1); // index is zero based
std::cout << index;
}
return 0;
}
By using std::find_if you can get the position of item1 by iterator, which you can use with std::distance to get the count of elements that are in front of it.
Credits for the explode method go to this post: Is there an equivalent in C++ of PHP's explode() function?
There are many ways to Rome. Here an additional solution using a std::regex.
But main approach is the same as the accepted answer. Using modern C++17 language elements, it is a little bit more compact.
#include <iostream>
#include <string>
#include <regex>
#include <iterator>
#include <vector>
const std::regex re{ "," };
int main() {
std::string items{ "box,cat,dog,cat" };
// Split String and put all sub-items in a vector
std::vector subItems(std::sregex_token_iterator(items.begin(), items.end(), re, -1), {});
// Search and check if found and show result
if (auto it = std::find(subItems.begin(), subItems.end(), "dog"); it != subItems.end())
std::cout << "Found at position: " << std::distance(subItems.begin(), it) + 1 << '\n';
else
std::cout << "Not found.\n";
return 0;
}

string to numbers (vector array of int type)conversion

The function takes a string containing of comma(,) separated numbers as string and converts into numbers. Sometimes it produces a garbage value at the end.
vector<int> parseInts(string str)
{
int as[200]={0};
int i=0,j=0;
for(;str[i]!='\0';i++)
{
while(str[i]!=','&&str[i]!='\0')
{as[j]= as[j]*10 +str[i] -'0';
i++;}
j++;
}
vector<int>rr;
for(int i=0;i<j;i++)
rr.push_back(as[i]);
return rr;
}
If you're writing in C++, use C++ features instead of C-style string manipulation. You can combine std::istringstream, std::getline(), and std::stoi() into a very short solution. (Also note that you should take the argument by const reference since you do not modify it.)
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
std::vector<int> parseInts(std::string const & str) {
std::vector<int> values;
std::istringstream src{str};
std::string buf;
while (std::getline(src, buf, ',')) {
// Note no error checking on this conversion -- exercise for the reader.
values.push_back(std::stoi(buf));
}
return values;
}
(Demo)
The code doesn't handle whitespace and inputs with more than 200 numbers.
An alternative working solution:
#include <iostream>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <vector>
std::vector<int> parseInts(std::string s) {
std::replace(s.begin(), s.end(), ',', ' ');
std::istringstream ss(std::move(s));
return std::vector<int>{
std::istream_iterator<int>{ss},
std::istream_iterator<int>{}
};
}
int main() {
auto v = parseInts("1,2 , 3 ,,, 4,5,,,");
for(auto i : v)
std::cout << i << '\n';
}
Output:
1
2
3
4
5
You never really asked a question. If you are looking for an elegant method, then I provide that below. If you are asking us to debug the code, then that is a different matter.
First here is a nice utility for splitting a string
std::vector<std::string> split(const std::string& str, char delim) {
std::vector<std::string> strings;
size_t start;
size_t end = 0;
while ((start = str.find_first_not_of(delim, end)) != std::string::npos) {
end = str.find(delim, start);
strings.push_back(str.substr(start, end - start));
}
return strings;
}
First split the string on commas:
std::vector<std::string> strings = split(str, ',');
Then covert each to an int
std::vector<int> ints;
for (auto s : strings)
ints.push_back(std::stoi(s))

Read comma separated integers from getline()

How can I read separate integers from the code below?
while (getline(cin, line)) {
// for each integer in line do something.....
// myVector.push_back(each integer)
}
The input is like this: 1, 2, 3, 5 (separated by comma except the last integer).
Sample Input (ignore the line # part):
line1: 1, 2, 3, 4, 5
line2: 6, 7, 8, 9, 10
line3: 3, 3, 3, 3, 3
/// and so on...
I need to read the integers one by one, and let's say increment and print them.
I make use of a handy utility to split a string into pieces using a char delimeter:
std::vector<std::string> split(const std::string& str, char delim) {
std::vector<std::string> strings;
size_t start;
size_t end = 0;
while ((start = str.find_first_not_of(delim, end)) != std::string::npos) {
end = str.find(delim, start);
strings.push_back(str.substr(start, end - start));
}
return strings;
}
and then do something like this:
while (getline(cin, line)) {
std::vector<std::string> strings = split(line, ',');
for (const auto& str : strings) {
const int i = std::stoi(str);
// do something w i
}
}
By default, '\n' is the delimiter for std::getline(). You can specify ',' instead as the delimiter, eg:
string value;
while (getline(cin, value, ',')) {
int num = stoi(value);
...
}
Otherwise, you can use std::getline() with '\n' as the delimiter to read an entire line, and then use a separate std::istringstream to read values from that line, such as by using std::getline() with ',' as the delimiter, eg:
string line;
if (getline(cin, line)) {
istringstream iss(line);
string value;
while (getline(iss, value, ',')) {
int num = stoi(value);
...
}
}
Alternatively, you can use streaming extraction via operator>>, eg:
string line;
if (getline(cin, line)) {
istringstream iss(line);
int num;
while (iss >> num) {
...
iss.ignore(); // skip terminating comma/whitespace
}
}
I will show you several different approaches on how to tokenize a string:
Splitting a string into tokens is a very old task. There are many many solutions available. All have different properties. Some are difficult to understand, some are hard to develop, some are more complex, slower or faster or more flexible or not.
Alternatives
Handcrafted, many variants, using pointers or iterators, maybe hard to develop and error prone.
Using old style std::strtok function. Maybe unsafe. Maybe should not be used any longer
std::getline. Most used implementation. But actually a "misuse" and not so flexible
Using dedicated modern function, specifically developed for this purpose, most flexible and good fitting into the STL environment and algortithm landscape. But slower.
Please see 4 examples in one piece of code.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <regex>
#include <algorithm>
#include <iterator>
#include <cstring>
#include <forward_list>
#include <deque>
using Container = std::vector<std::string>;
std::regex delimiter{ "," };
int main() {
// Some function to print the contents of an STL container
auto print = [](const auto& container) -> void { std::copy(container.begin(), container.end(),
std::ostream_iterator<std::decay<decltype(*container.begin())>::type>(std::cout, " ")); std::cout << '\n'; };
// Example 1: Handcrafted -------------------------------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};
// Search for comma, then take the part and add to the result
for (size_t i{ 0U }, startpos{ 0U }; i <= stringToSplit.size(); ++i) {
// So, if there is a comma or the end of the string
if ((stringToSplit[i] == ',') || (i == (stringToSplit.size()))) {
// Copy substring
c.push_back(stringToSplit.substr(startpos, i - startpos));
startpos = i + 1;
}
}
print(c);
}
// Example 2: Using very old strtok function ----------------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};
// Split string into parts in a simple for loop
#pragma warning(suppress : 4996)
for (char* token = std::strtok(const_cast<char*>(stringToSplit.data()), ","); token != nullptr; token = std::strtok(nullptr, ",")) {
c.push_back(token);
}
print(c);
}
// Example 3: Very often used std::getline with additional istringstream ------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};
// Put string in an std::istringstream
std::istringstream iss{ stringToSplit };
// Extract string parts in simple for loop
for (std::string part{}; std::getline(iss, part, ','); c.push_back(part))
;
print(c);
}
// Example 4: Most flexible iterator solution ------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
//
// Everything done already with range constructor. No additional code needed.
//
print(c);
// Works also with other containers in the same way
std::forward_list<std::string> c2(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
print(c2);
// And works with algorithms
std::deque<std::string> c3{};
std::copy(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {}, std::back_inserter(c3));
print(c3);
}
return 0;
}

istream_iterator deal with string with pipe [duplicate]

This question already has answers here:
How do I iterate over the words of a string?
(84 answers)
Closed 4 years ago.
If I have a std::string containing a comma-separated list of numbers, what's the simplest way to parse out the numbers and put them in an integer array?
I don't want to generalise this out into parsing anything else. Just a simple string of comma separated integer numbers such as "1,1,1,1,2,1,1,1,0".
Input one number at a time, and check whether the following character is ,. If so, discard it.
#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;
}
Something less verbose, std and takes anything separated by a comma.
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 );
}
Yet another, rather different, approach: use a special locale that treats commas as white space:
#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];
}
};
To use this, you imbue() a stream with a locale that includes this facet. Once you've done that, you can read numbers as if the commas weren't there at all. Just for example, we'll read comma-delimited numbers from input, and write then out one-per line on standard output:
#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;
}
The C++ String Toolkit Library (Strtk) has the following solution to your problem:
#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;
}
More examples can be found Here
Alternative solution using generic algorithms and 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());
Lots of pretty terrible answers here so I'll add mine (including test program):
#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;
}
Nice properties:
No dependencies (e.g. boost)
Not an insane one-liner
Easy to understand (I hope)
Handles spaces perfectly fine
Doesn't allocate splits if you don't want to, e.g. you can process them with a lambda as shown.
Doesn't add characters one at a time - should be fast.
If using C++17 you could change it to use a std::stringview and then it won't do any allocations and should be extremely fast.
Some design choices you may wish to change:
Empty entries are not ignored.
An empty string will call f() once.
Example inputs and outputs:
"" -> {""}
"," -> {"", ""}
"1," -> {"1", ""}
"1" -> {"1"}
" " -> {" "}
"1, 2," -> {"1", " 2", ""}
" ,, " -> {" ", "", " "}
You could also use the following function.
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) );
It would be a good idea to check for conversion errors in strtol(), of course. Maybe the code may benefit from some other error checks as well.
I'm surprised no one has proposed a solution using std::regex yet:
#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]); } );
}
This function inserts all integers at the back of the input vector. You can tweak the regular expression to include negative integers, or floating point numbers, etc.
#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);
}
}
Bad input (for instance consecutive separators) will mess this up, but you did say simple.
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;
}
I cannot yet comment (getting started on the site) but added a more generic version of Jerry Coffin's fantastic ctype's derived class to his post.
Thanks Jerry for the super idea.
(Because it must be peer-reviewed, adding it here too temporarily)
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];
}
};
This is the simplest way, which I used a lot. It works for any one-character delimiter.
#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;
}
simple structure, easily adaptable, easy maintenance.
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];
}
}
in the end you will have a vector of strings with every element in the sentence separated by spaces. empty strings are saved as separate items.
Simple Copy/Paste function, based on the boost tokenizer.
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++;
}
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;
}