Say you have
char *= "name:454";
What is the best way to parse name and the number, thus
std:string id would equal to "name";
double d would equal to 454;
STL please, no boost.
Say you have
char *= "name:454";
What is the best way to parse name and the number, thus
std:string id would equal to "name";
double d would equal to 454;
STL please, no boost.
You want to look at the strtok
function using ':'
as the token. Here is an example:
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "name:454";
char* c = strtok(str, ":");
while (c != NULL)
{
printf("%s\n", c);
c = strtok(NULL, ":");
}
return 0;
}
Not the stl solution you asked for; however, sooner or later you'll need to parse more complicated expressions (hint - sooner than you expect), at which point you will need regular expressions - so why not start now. Your expression is captures by:
^(\w+):(\d+)$
I'm no boost fanatic, but their regexp library is nice.
#include <iostream>
#include <sstream>
#include <string>
int main() {
/* output storage */
std::string id;
double d;
/* convert input to a STL string */
std::string s("name:454");
size_t off = std::string::npos;
/* smart replace: parsing is easier with a space */
if ((off = s.find(':')) != std::string::npos) { // error check: all or none
s = s.replace(off, 1, 1, ' ');
std::istringstream iss(s);
iss >> id >> d;
std::cout << "id = " << id << " ; d = " << d << '\n';
}
return 0;
}
Though, I'd just write my own parser or use the C scanner function for speed.
I would write my own. The basic idea would be to read one character at a time from the stream. If it isn't a colon, append it to the id string. If it is, skip it, then use the istream >> operator to load an integer, double float, or whatever is needed. Then you probably put the result into a std::map.
Another possibility is to use an already written parser for a simple format like INI.
Here is one: http://code.jellycan.com/SimpleIni/
I looked at the code for SimpleIni and it isn't very C++ and STL'ish, but do you really care?
template < typename T >
T valueFromString( const std::string &src )
{
std::stringstream s( src );
T result = T();
s >> result;
return result;
}
std::string wordByNumber( const std::string &src, size_t n, const std::string &delims )
{
std::string::size_type word_begin = 0;
for ( size_t i = 0; i < n; ++i )
{
word_begin = src.find_first_of( delims, word_begin );
}
std::string::size_type word_end = src.find_first_of( delims, word_begin );
word_begin = std::string::npos == word_begin || word_begin == src.length() ? 0 : word_begin + 1;
word_end = std::string::npos == word_end ? src.length() : word_end;
return src.substr( word_begin, word_end - word_begin);
}
char *a = "asdfsd:5.2";
std::cout << wordByNumber( a, 0, ":" ) << ", " << valueFromString< double > ( wordByNumber( a, 1, ":" ) );
PS: in previous revision I've posted wordByNumber - which skipped neighbored delimiters (e.g.:::), in current revision they are treated as empty word.