On Nov 7, 7:24 am, "(2b|!2b)==?" <void-s...@ursa-major.com> wrote:
I am expecting a string of this format:
"id1:param1,param2;id2:param1,param2,param3;id"
The tokens are seperated by semicolon ";"
However each token is really a struct of the following format:
struct mst_
{
int id;
struct params_* parms ; //0 or more
struct mst_ *next ;
};
where:
struct params_
{
double argval;
struct params_ * next;
};
Could anyone suggest an elegant way to parse strings with the specified
formatting into a linked list (struct mst_) ?
Here is one way to do so:
#include <stdio.h>
#include <malloc.h>
struct params
{
double arg;
params* next;
};
struct mst
{
int id;
params* params;
mst* next;
};
void mst_print(FILE* file, mst* head)
{
for(;head; head = head->next)
{
fprintf(file, "%d", head->id);
if(head->params)
{
char sep = ':';
for(params* param = head->params; param; param = param-
next)
{
fprintf(file, "%c%f", sep, param->arg);
sep = ',';
}
}
fprintf(file, ";");
}
}
mst* mst_destroy(mst* head)
{
while(head)
{
mst* node = head;
head = head->next;
for(params* node_params = node->params; node_params;)
{
params* p = node_params;
node_params = node_params->next;
free(p);
}
free(node);
}
return NULL;
}
mst* mst_parse(char const** input)
{
mst *head = NULL, **tail = &head;
while(*input)
{
// parse id
int id, eaten = 0;
sscanf(*input, "%d%n", &id, &eaten);
if(!eaten)
return head;
*input += eaten;
// allocate the next mst node and initialise it
mst* next = (mst*)malloc(sizeof(mst));
if(!next)
return mst_destroy(head);
next->id = id;
next->params = NULL;
next->next = NULL;
// append the node to the list
*tail = next;
tail = &next->next;
// parse params
if(':' == **input)
{
params** tail_params = &next->params;
++*input;
for(;;)
{
double arg;
eaten = 0;
sscanf(*input, "%lf%n", &arg, &eaten);
if(!eaten)
return head;
*input += eaten;
// allocate the next params node and initialise it
params* next_params =
(params*)malloc(sizeof(params));
if(!next_params)
return mst_destroy(head);
next_params->arg = arg;
next_params->next = NULL;
// append to the params list
*tail_params = next_params;
tail_params = &next_params->next;
// see if there are more params
if(',' != **input)
break;
++*input;
}
}
// see if there are more ids
if(';' != **input)
break;
++*input;
}
return head;
}
char const* inputs[] = {
""
, "1"
, "1:1.0"
, "1:1.0,2.0"
, "1:1.0,2.0;2:11.0,22.0;"
, "1:1.0,2.0;2:11.0,22.0;qwerty"
, NULL
};
int main()
{
for(char const** i = inputs; *i; ++i)
{
char const* input = *i;
printf("parsing '%s': ", input);
mst* head = mst_parse(&input);
if(*input)
printf("<choked at postion %d> ", (int)(input - *i));
mst_print(stdout, head);
mst_destroy(head);
printf("\n");
}
}
Output:
parsing '':
parsing '1': 1;
parsing '1:1.0': 1:1.000000;
parsing '1:1.0,2.0': 1:1.000000,2.000000;
parsing '1:1.0,2.0;2:11.0,22.0;':
1:1.000000,2.000000;2:11.000000,22.000000;
parsing '1:1.0,2.0;2:11.0,22.0;qwerty': <choked at postion 22>
1:1.000000,2.000000;2:11.000000,22.000000;
--
Max
Thanks Maxim. This is exactly what I needed.