Skip to main content
gamedev.net
🔒 Locked

A Small Programming Challenge

Started by dave 12 replies 2.7k views
Original Post
dave
dave
What is the most elegant solution that you can come up with for tokenising the following string without using any pre-existing function: "0,0,0,0" into four integers. I have done this many a time and can never remember how i did it. How do you do it? Dave
technomancer
technomancer
by pre-existing function do you mean like strtok or even atoi ?? if you can use atoi then its pretty easy cause atoi will convert to an integer up to the first non-numeric so just atoi increase your pointer by 2 and atoi again rinse and repeat :)
MaulingMonkey
MaulingMonkey
Depends on how you define elegant.

Do we want to handle non-base-10? Non-latin?
Do we want to handle signed numbers?
Do we want to handle N != 4 for number of numbers?
What kind of error checking should we perform?

The "hard code everything, checks be damned" approach:

int n_array[4] = {0,0,0,0}, *n = n_array;const char *string = "0,0,0,0", *c = string;for ( const char *c = string ; *c != '\0' ; ++c ) {    assert( n != end(n_array) );    /* for the unenlightened: end(n_array) returns (n_array+4) here -- one past     * the last element in the array -- I refuse to do without this function in     * my example ;-)     */    if( '0' <= *c && *c <= '9' ) *n = (*n * 10) + (*c - '0');    else if ( *c == ',' ) ++n;    else if ( *c == ' ' ); //do nothing    else assert(!"reached"); //to be noted in function preconditions:  string must be valid.}


Language is C++.
dave
dave
This is a solution i just came up with, has limitations but serves the purpose:
	GUIVector4	GUIXmlLoader::StringToGUIVector4( const String& dims )	{		GUIVector4	temp;		UnsignedInt	count = 0;		UnsignedInt i, j;		i = j = 0;		for ( UnsignedInt i = 0; i < dims.length(); ++i )		{			for ( j = i; j < dims.length(); ++j )			{				if ( dims[j] == ',' )					break;			}			temp[count] = ATOF( dims.substr( i, j ).c_str() );			++count;			i = j;		}		return temp;	}


Dave
Nathan Baum
Nathan Baum
Quote:
Original post by Dave
What is the most elegant solution that you can come up with for tokenising the following string without using any pre-existing function:

"0,0,0,0"

into four integers.

I have done this many a time and can never remember how i did it. How do you do it?

Dave


int tokens[] = { 0, 0, 0, 0 };


I've applied some constant folding.
ToohrVyk
ToohrVyk
It all depends on your definition of pre-existing function. I generally consider standard library definitions to be language constructs, and not pre-existing functions. All of this runs without checks, which should obviously be added to the mix.

The most elegant in my opinion would be:

PHP
list($i1,$i2,$i3,$i4) = explode(",",$str);


A less beautiful version would be:

C++
std::stringstream conversion;int i1, i2, i3, i4;char comma;conversion << str;conversion >> i1 >> comma >> i2 >> comma >> i3 >> comma >> i4;


And, while we're at it, some fun with generated lexers:

OCaml
let (i1,i2,i3,i4) =   begin parser    | [< 'Int i1; 'Key ",";          'Int i2; 'Key ",";          'Int i3; 'Key ",";          'Int i4 >] -> (i1,i2,i3,i4)    | _ -> failwith "Syntax error"  end ( (Genlex.make_lexer [","]) (Stream.of_string str) );;
Nathan Baum
Nathan Baum
// Tokenize the integer list `string` into the array `list`.// Returns the number of tokens in the string, but only elements// `list[0 .. max-1]` are filled in, even if there are more// tokens. If `list` is null, no tokens are stored.int parse_int_list (const char *string, int *list, int max){  int c, count = 0;  if (list)    for (int i = 0; i < max; ++i)      list = 0;  while (c = *string++)    if (c >= '0' && c <= '9' && count < max && list)      list[count] = list[count] * 10 + (c - '0');    else if (c == ',')      ++count;  return ++count;}


Quote:
Original post by Dave
without using any pre-existing function


Quote:
Original post by Dave
This is a solution i just came up with, has limitations but serves the purpose:
	GUIVector4	GUIXmlLoader::StringToGUIVector4( const String& dims )	{		GUIVector4	temp;		UnsignedInt	count = 0;		UnsignedInt i, j;		i = j = 0;		for ( UnsignedInt i = 0; i < dims.length(); ++i )		{			for ( j = i; j < dims.length(); ++j )			{				if ( dims[j] == ',' )					break;			}			temp[count] = ATOF( dims.substr( i, j ).c_str() );			++count;			i = j;		}		return temp;	}


Dave


Isn't that using a whole bunch of preexisting functions?
Deyja
Deyja
To meet the OP's requirments, it must not call anything, not even an operator on a non-built in type.

Incidentally... Boost::tokenizer and boost::lexical_cast?
Zahlman
Zahlman
Quote:
without using any pre-existing function


Why would you do that? Programming is about reuse.
nemesisgeek
nemesisgeek
This code is plain garden-variety C++, and could be translated to strict C by replacing //...\n comments with /*...*/ comments, and moving all variable declarations to the beginning of the code.

Fully commented version:
//This is our input dataconst char in_str[]="0,0,0,0";//Do a strlen without calling any library functionsint len=0;while(in_str[len]!='\0')  len++;//Now tokenize the stringint output[4];     //Must output four integersint pos=0;for(int i=0;i<len;i++){  //Skip commas  if(in_str==',')    continue;  //Read in the integer  //Note that this doesn't handle 2-digit numbers like "27",  //but that could be done with a bit more code.  output[pos++]=in_str - '0';}


More compact version (same code but less lines - harder to understand)
const char in_str[]="0,0,0,0";int len=0;while(in_str[len]!='\0')  len++;int output[4];int pos=0;for(int i=0;i<len;i++)  if(in_str!=',')    output[pos++]=in_str - '0';


And if you really want to obfuscate your code:
const char in_str[]="0,0,0,0";int len=0,i=0,pos=0;int output[4];while(in_str[len]!='\0'){len++;}for(;i<len;i++){if(in_str!=','){ output[pos++]=in_str - '0';}}
hackerkey://v4sw7+8CHS$hw6+8ln6pr8O$ck4ma4+9u5Lw7VX$m0l5Ri8ONotepad++/e3+8t3b8AORTen7+9a17s0r4g8OP
dave
dave
The purpose of this was to see how people would go about writing an algorithm without using a string tokenizing function.

And no, ofcourse you wouldn't put it in your production code.
SunTzu
SunTzu
Quote:
The purpose of this was to see how people would go about writing an algorithm without using a string tokenizing function.


I wouldn't. I have better things to do with my time. But, y'know... each to their own.

Quote:
I have done this many a time and can never remember how i did it.


I wonder how much time you've wasted doing that? It is your time, though, I suppose, and you may do with it as you wish...
eq
eq
My C/C++ contribution:
int i0, i1, i2, i3;sscanf(textString, "%d,%d,%d,%d", i0, i1, i2, i3);

ApochPiQ
ApochPiQ
Quote:
Original post by eq
My C/C++ contribution:
*** Source Snippet Removed ***


Boom, instant crash.

sscanf's parameters need to be pointers to the variables you want to fill in... which is part of why it's such a bad idea to use the C string functions when C++ library code is available. (Incidentally, that post is also a good illustration of why mucking about with raw string parsing is not really wise when library code is available to do the same job.)

In any case, I think this violates the OP's (rather silly) requirement of not using library code.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.