2
P|20131120|20131120
C|F|350.0|50.0|350.0|16.67|50.0|16.67|1400.0|Y|15.0|
C|H|610.3|87.19|610.3|29.06|87.19|29.06|2441.2|Y|15.0|
C|L|1386.0|198.0|1386.0|66.0|198.0|66.0|5544.0|Y|15.0|
C|Z|1286.0|183.71|1286.0|61.24|183.71|61.24|5144.0|Y|15.0|

P|20131121|20131121
C|A|323.65|46.24|323.65|15.41|46.24|15.41|1294.6|Y|15.0|
C|B|323.65|46.24|323.65|15.41|46.24|15.41|1294.6|Y|15.0|
C|D|365.65|52.24|365.65|17.41|52.24|17.41|1462.6|Y|15.0|
C|E|365.65|52.24|365.65|17.41|52.24|17.41|1462.6|Y|15.0|

Above is the message coming from one server as a single string. Now i want to parse it and store in a structure for the processing in C language.

Here for one P(Period) row, there can be many C(Class) rows. '|' is field delimiter which should be ignored while storing into the structure. Here the number of C(Class) rows are not fixed for a P.

Can anybody suggest me in C, how should i declare the Structures and parse and store these fields into it. As per my guess i will have to declare the structure array at run time for class(C) rows because it is not fixed. One thing is fixed: P(Period) row size is always 17 byte (or charector) excluding pipe(|) and C(Class) row size is 61 character excluding pipe(|. Dear All, can please anybody help me in C logic or code.

4
  • I am not sure If i get your question but why don't you use link list with P as header node and rest C's as normal nodes and add whatever details you want to add in the structure declaration? Commented Dec 5, 2013 at 5:18
  • But before that, he has to get the data present in the string isnt it ? Commented Dec 5, 2013 at 5:21
  • Dear codeomnitrix, can u please help me some sample structure declarations.. It will really give me some basic idea... Thanks in advance Commented Dec 5, 2013 at 5:29
  • @user3064342: If you want to address anyone, use @User_name henceforth. Thats the SO system here Commented Dec 5, 2013 at 6:22

5 Answers 5

1

There are multiple parsing levels for this string

  1. Use token as P/C for doing the first level of filtering

  2. Use token as | as second level of filtering ( Inside which youi have H/Y etc which you need to take into consideration as well while copying it to structure members).

Accordingly you can have structure declartion .

You can visit this article strtok usage

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

1 Comment

I was going to suggest using strtok in combination with state machine. But given that the structure of each "P" and "C" records looks fixed I think your solution is better.
1

Here you go -

struct node{
    char startChar, endChar;
    float numArr[8];
    struct node *next;
}

struct headerNode{
   int num1, num2;
   struct node *first;
}

After that you can make use of

createList() //create a blank list with header node.
createNode() //a C node everytime you need it.

Rest is merely parsing the string.

I hope this will help.

Comments

1
struct c_struct
{
    char c_content[61];
    struct c_strcut *next_c_strcut; //pointer to next class
};

struct PC_struct
{
    char p_content[17];
    struct c_struct *c_head; // pointer to first node
    struct PC_struct *PC_struct; // pointer to next pc 
};

Comments

1
#include <stdio.h>
#include <string.h>

#define MAX_CLASSES 100
#define MAX_PERIODS 100

struct Class{
  char a, i;
  float b,c,d,e,f,g,h,j;
};

struct Period{
  char date1[10], date2[10];
  struct Class classes[MAX_CLASSES];
};

struct Period periods[MAX_PERIODS];

int main(void){
  //use sscanf to parse the data
  //for example, (assuming data is in char *s),
  //sscanf(s, "P|%s|%s\n", periods[0].date1, periods[0].date2);
  return 0;
}

Comments

1

The most critical part is safely parsing the input, after that, interpretation, validation and organization of the pre-structured data is a breeze, I made only the hard part (input handling) below

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char *data =
  "P|20131120|20131120\n"
  "C|F|350.0|50.0|350.0|16.67|50.0|16.67|1400.0|Y|15.0|\n"
  "C|H|610.3|87.19|610.3|29.06|87.19|29.06|2441.2|Y|15.0|\n"
  "C|L|1386.0|198.0|1386.0|66.0|198.0|66.0|5544.0|Y|15.0|\n"
  "C|Z|1286.0|183.71|1286.0|61.24|183.71|61.24|5144.0|Y|15.0|\n"
  "\n"
  "P|20131121|20131121\n"
  "C|A|323.65|46.24|323.65|15.41|46.24|15.41|1294.6|Y|15.0|\n"
  "C|B|323.65|46.24|323.65|15.41|46.24|15.41|1294.6|Y|15.0|\n"
  "C|D|365.65|52.24|365.65|17.41|52.24|17.41|1462.6|Y|15.0|\n"
  "C|E|365.65|52.24|365.65|17.41|52.24|17.41|1462.6|Y|15.0|\n"
  ;

struct columns
{
  char *cols[12]; /* 16 pointers */
} rows[100];  /* bss, all zero */

#define N_COLS (sizeof(struct columns)/sizeof(char*))
#define N_ROWS (sizeof(rows)/sizeof(struct columns))

int main(void)
{
  char *rowsdata, *s;
  char **curcol  = rows->cols;
  char **lastcol = rows->cols + N_COLS;
  int row, i;

  rowsdata = s = strdup(data);
  if (rowsdata == 0) {
    perror("strdup");
    exit(1);
  }

  for (row=0; row < N_ROWS; s++) {
    if (*s == '|') {
      *s = 0;
      if (++curcol == lastcol) {
        puts("error: too much columns");
        exit(1);
      }
    } else if (*s == '\n') {
      *s = 0;
      row++;
      curcol  = (rows + row)->cols;
      lastcol = (rows + row)->cols + N_COLS;
    } else if (*curcol == 0) {
      *curcol = s;
    } else if (*s == 0) break;
  }

  /* do your logic here
   */

  for (i=0; i<row; i++) {
    curcol = (rows + i)->cols;
    lastcol = (rows + i)->cols + N_COLS;
    while (*curcol && curcol < lastcol) {
      printf("[%s]", *curcol);
      curcol++;
    }
    printf("\n");
  }

  /* free rowsdata only when done with rows
   */
  free(rowsdata); rowsdata = 0;

  return 0;
}

the code above relies heavily on pointer arithmetic

*edit: rename from 'cols' to 'rows' and 'cells' to 'cols', makes more sense

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.