25

How can I split a string such as "102:330:3133:76531:451:000:12:44412 by the ":" character, and put all of the numbers into an int array (number sequence will always be 8 elements long)? Preferably without using an external library such as boost.

Also, I'm wondering how I can remove unneeded characters from the string before it's processed such as "$" and "#"?

3
  • 5
    @CaptainObvlious that is not a sufficient comment - please specify the version of elven magic you are using Commented Dec 24, 2013 at 5:13
  • @johny pretty much the same question, however I'm guessing OP doesn't know how to convert from a string to a number either. Commented Dec 24, 2013 at 5:32
  • what about good old strtok? Commented Dec 24, 2013 at 5:52

9 Answers 9

20

stringstream can do all these.

  1. Split a string and store into int array:

    string str = "102:330:3133:76531:451:000:12:44412"; std::replace(str.begin(), str.end(), ':', ' '); // replace ':' by ' ' vector<int> array; stringstream ss(str); int temp; while (ss >> temp) array.push_back(temp); // done! now array={102,330,3133,76531,451,000,12,44412} 
  2. Remove unneeded characters from the string before it's processed such as $ and #: just as the way handling : in the above.

PS: The above solution works only for strings that don't contain spaces. To handle strings with spaces, please refer to here based on std::string::find() and std::string::substr().

Sign up to request clarification or add additional context in comments.

4 Comments

When I try your code I get these errors: (no operator "==" matches these operands operand types are: char == const char [2]) (a value of type "const char *" cannot be assigned to an entity of type "char")
instead of manually replacing the colons, you can just use std::replace(str.begin(), str.end(), ':', ' ');
this is a very specific answer that does not work if the strings contain spaces.
@MartinMassera Thanks for pointing this out. Update the answer to intergrate this. Thanks.
11

The standard way in C is to use strtok like others have answered. However strtok is not C++-like and also unsafe. The standard way in C++ is to use std::istringstream

std::istringstream iss(str); char c; // dummy character for the colon int a[8]; iss >> a[0]; for (int i = 1; i < 8; i++) iss >> c >> a[i]; 

In case the input always has a fixed number of tokens like that, sscanf may be another simple solution

std::sscanf(str, "%d:%d:%d:%d:%d:%d:%d:%d", &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8); 

Comments

7

I had to write some code like this before and found a question on Stack Overflow for splitting a string by delimiter. Here's the original question: link.

You could use this with std::stoi for building the vector.

std::vector<int> split(const std::string &s, char delim) { std::vector<int> elems; std::stringstream ss(s); std::string number; while(std::getline(ss, number, delim)) { elems.push_back(std::stoi(number)); } return elems; } // use with: const std::string numbers("102:330:3133:76531:451:000:12:44412"); std::vector<int> numbers = split(numbers, ':'); 

Here is a working ideone sample.

3 Comments

Is there an easy way to store it in an array instead of a vector?
@user2705775 std::copy(vector.begin(), vector.end(), std::begin(array)).
@user2705775 the problem with storing it in an array is that you don't appear to know the number of characters before fully parsing the string. You can go with what remyabel if you really need it, but I don't quite see the point.
1

True ! there's no elven magic

Its kinda answered here too

#include <cstring> #include <iostream> #include<cstdlib> #include<vector> int main() { char input[100] = "102:330:3133:76531:451:000:12:44412"; char *token = std::strtok(input, ":"); std::vector<int> v; while (token != NULL) { v.push_back( std::strtol( token, NULL, 10 )); token = std::strtok(NULL, ":"); } for(std::size_t i =0 ; i < v.size() ; ++i) std::cout << v[i] <<std::endl; } 

Demo Here

Comments

1

To remove characters '#' and '$' you can use standard algorithm std::remove_if. However take into account that if there is for example the following string "12#34" then after removing '#' you will ge "1234". If you need that the resulted string will look as "12 34" or "12:34" then instead of std::remove_if it is better to use std::replace_if.

Below there is a sample code that performs the task. You need to include headers

#include <iostream> #include <cstdlib> #include <cstring> #include <algorithm> int main() { char s[] = "102:$$330:#3133:76531:451:000:$12:44412"; std::cout << s << std::endl; char *p = std::remove_if( s, s + std::strlen( s ), []( char c ) { return ( c == '$' || c == '#' ); } ); *p = '\0'; std::cout << s << std::endl; const size_t N = 8; int a[N]; p = s; for ( size_t i = 0; i < N; i++ ) { a[i] = strtol( p, &p, 10 ); if ( *p == ':' ) ++p; } for ( int x : a ) std::cout << x << ' '; std::cout << std::endl; } 

The output is

102:$$330:#3133:76531:451:000:$12:44412 102:330:3133:76531:451:000:12:44412 102 330 3133 76531 451 0 12 44412 

Comments

0

Here's one way... not the cleverest but fast to write (8 repetition's verging on warranting a loop though). This approach to parsing is quite widely useful so good to learn. !(iss >> c) ensures there's no trailing non-whitespace characters in the string.

std::istringstream iss(the_string); char c; int n[8]; if (iss >> n[0] >> c && c == ':' && iss >> n[1] >> c && c == ':' && iss >> n[2] >> c && c == ':' && iss >> n[3] >> c && c == ':' && iss >> n[4] >> c && c == ':' && iss >> n[5] >> c && c == ':' && iss >> n[6] >> c && c == ':' && iss >> n[7] && !(iss >> c)) ... 

4 Comments

Why even bother checking c == ':'?
@Beta: it's generally considered a reasonable practice to check input looks as expected... if the colons are missing it might mean there's something else bogus about the input. For example, if someone passed "3.14 12.78 999.1 38.6" it would parse as [ 3 14 2 78 99 1 8 6 ] otherwise. (I get really tired of seeing S.O. questions where I/O problems would have been found if people checking input and output properly).
I'm getting an error "no operator ">>" matches these operands. operand types are: std::istringstream >> int"
@user2705775: did you #include <sstream>?
0

You can use strtok() for split your string, perhaps in while loop.

When you get individual string then can use atoi(xxx) for conversion in ints.

1 Comment

0

Another solution using the regular expression features in C++11.

#include <algorithm> #include <iostream> #include <iterator> #include <ostream> #include <regex> #include <sstream> #include <string> #include <vector> int main() { const std::string s = "102:330:3133:76531:451:000:12:44412"; // Replace each colon with a single space const std::regex pattern(":"); const std::string r = std::regex_replace(s, pattern, " "); std::istringstream ist(r); std::vector<int> numbers; std::copy(std::istream_iterator<int>(ist), std::istream_iterator<int>(), std::back_inserter(numbers)); // We now have a vector of numbers // Print it out for (auto n : numbers) { std::cout << n << " "; } std::cout << std::endl; return 0; } 

Comments

0
#include <stdio.h> #include <string.h> int main () { char str[] ="102:330:3133:76531:451:000:12:44412"; char * pch; printf ("Splitting string \"%s\" into tokens:\n",str); pch = strtok (str,":"); while (pch != NULL) { printf ("%s\n",pch); pch = strtok (NULL, ":"); } return 0; } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.