Column Based ASCII Analysis in C

I am trying to parse text containing integers in a fixed number of columns. For example, my input file might look like this:

=1=2=3 =4=5=6 =8=910 

where the = sign represents spaces in the input. An equal sign is not in the input file; I just put it there for illustrative purposes. Each integer is contained in two columns without zero padding, so the third row is not a typo: it is 8, 9, and then 10.

The sscanf standard does not work because it first removes the spaces and then applies the format string. For example, I tried:

 sscanf(buf, "%2d%2d%2d", &int1, &int2, &int3) 

but he finishes parsing the third line as 8, 91 and 0.

Is there a way to do this without manually pulling a data column through the column?

+4
source share
4 answers

You can do this in many ways. Using sscanf (or strtol ), you have (at least) these two parameters:

  • Make a copy of the column and then sscanf it:

     char temp[COL_SIZE+1] = {'\0'}; /* last character will always be NUL */ for (i = 0; i < col_count; ++i) { memcpy(temp, buf + i * COL_SIZE, COL_SIZE * sizeof(*buf)); /* "* sizeof" actually unnecessary */ sscanf(temp, "%d", &num[i]); /* or use strtol */ } 
  • You can also do this a little more efficiently, given that you will not do this in a constant string , especially never, in a string literal :

     for (i = 0; i < col_count; ++i) { char temp; int column_beg = i * COL_SIZE; int column_end = column_beg + COL_SIZE; temp = buf[column_end]; buf[column_end] = '\0'; sscanf(buf + column_beg, "%d", &num[i]); /* or use strtol */ buf[column_end] = temp; } 

    What it does is insert '\0' after each column, read it, and then restore the original character. If this is done in a string literal, this will be undefined behavior.

I personally recommend the first method.

+1
source

You can do this by the symbol:

 #include <ctype.h> #include <stdio.h> int main(void) { int val; char input[] = "=8=910"; char *p = input; while (*p) { val = 0; if (isdigit((unsigned char)*p)) val = *p - '0'; // 1st digit p++; val *= 10; // 2nd val += *p++ - '0'; // digit printf("val: %d\n", val); } return 0; } 
+1
source

You can use the scanf() and "%2c" qualifier to read in two characters at the correctly zero end of the array, and then convert it to decimal (using strtol() or something like that) ... but this butt - ugly. Again, not uglier than the format itself.

Generally speaking, *scanf() is a very poor choice for parsing input data, due to this somewhat tangible behavior if the input is malformed. You should probably read the file in the internal buffer in the long run and do your own parsing / error handling.

0
source

Without using scanf . Must be fast ...

 void parse_columns(const char *line) { char buf[3]; buf[2] = '\0'; int i = 0; for (const char *c = &line[0]; *c; c++, i++) { buf[i] = *c; if (1 == i) { printf("%d\n", atoi(buf)); i = -1; } } } 
0
source

Source: https://habr.com/ru/post/1412584/


All Articles