Search code examples
cscanfreadfiledata-manipulationfgetc

Can't figure out how to isolate number and replace it


What i have done is using the first set of code i extracted the data and put it into a new file so it is only the values

This is my input file for first set of code:

original input

This is my input file for second set of code which is my main problem:

second set of input code

then in second set of code is where the new file is being read so it outputs the numbers using fgetc, how could I now apply a simple formula using this? specifically the formula would be turning any 10 value into a 0 value i tried that and since fgetc is unsigned char i try using the binary number for 10 in the if statement

this is my code so far:

#include<stdio.h> 

int main() 
{ 
    FILE* ptr = fopen("Data.txt","r"); 
    if (ptr==NULL) 
    { 
        printf("no such file."); 
        return 0; 
    } 

    FILE*fp = fopen("/data flow/NEWdata.txt", "w+");

        int x;
  int count=0;
    char buf[100];
    fscanf(ptr,"%*s %*s %*s %*s %*s %*s %*s %s ",buf); //skip first line and stuff before first value(column names)
    while (fscanf(ptr,"%*s %*s %*s %*s %s  ",buf)==1) 
    {

        fprintf(fp, "%s\n",buf);
    }
    fclose(fp); 
    return 0; 
} 

Second set of code

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

int main () {
   FILE *fp;
   char str[100];

   /* opening file for reading */
   fp = fopen("NEWdata.txt" , "r");
   if(fp == NULL) {
      perror("Error opening file");
      return(-1);
   }
   int i;
   while( fgets (str, 100, fp)!=NULL ) {
      /* writing content to stdout */
      sscanf (str,%u,i);
    printf(%u,i);

   }
   fclose(fp);

   return(0);
}

my supposedly command line enter image description here

error im getting is below enter image description here

 if (measure = 10)
            fprintf (ofp, "%f\n", measure - 10);
        else
            fprintf (ofp, "%f\n", measure);
#include <stdio.h>

#define MAXC 1024       /* if you need a constant, #define one (or more) */
#define MAXF   32

int main (int argc, char **argv) {

    char buf[MAXC];     /* buffer to hold each line read from file */
    size_t n = 0;       /* line counter */
   FILE *fp, *ofp;     /* file pointer, output file pointer */

    if (argc < 3 ) {    /* validate 2 arguments given for in/out filenames */
        fprintf (stderr, "error: insufficient input,\n"
                         "usage: %s filename outfilename\n", argv[0]);
        return 1;
    }

    /* open file/validate file open for reading */
    if ((fp = fopen ("Data.txt", "r")) == NULL) {
        perror ("fopen-argv[1]");
        return 1;
    }

    if ((ofp = fopen ("NEWdata.txt", "w")) == NULL) {
        perror ("fopen-argv[2]");
        return 1;
    }

    if (!fgets (buf, MAXC, fp)) {   /* read/discard 1st line */
        fputs ("error: EOF on read of first line.\n", stderr);
        return 1;
    }

    while (fgets (buf, MAXC, fp)) { /* read all remaining lines */
        char date[MAXF], time[MAXF], prod[MAXF], unit[MAXF];
        double measure;

        if (sscanf (buf, "%s %s %s %lf %s", /* validate all 5 fields */
                    date, time, prod, &measure, unit) != 5) {
            fprintf (stderr, "error: invalid format, line: %zu\n", n + 1);
            continue;
        }

        /* do whatever you need with the separated values.
         * if measure is 10.xx, then make measure 0.xx
         */
        if (measure = 10)
            fprintf (ofp, "%f\n", measure - 10);
        else
            fprintf (ofp, "%f\n", measure);

        n++;    /* increment line counter */
    }
}

Solution

  • If I understand correctly and you want to read the values from Data.txt and, if the value of Measurement is 10, you want to set the value to 0. As noted in my comment, your Measurement values is a floating-point number (double is used below). The comparison of floating point numbers is inherently inexact due to all numbers not being able to be represented exactly in floating-point format. (10.0 can be represented exactly, but be aware of the limitations). See Is floating point math broken? and Why Are Floating Point Numbers Inaccurate?

    Before getting there, Avoid Hardcoding Filenames or using Magic-Numbers in your code. main() takes arguments that allow you to pass information to your code. You can simply pass the filename to read as the first argument to your program or take the filename as input. e.g.

    #include <stdio.h>
    
    #define MAXC 1024       /* if you need a constant, #define one (or more) */
    #define MAXF   32
    
    int main (int argc, char **argv) {
    
        char buf[MAXC];     /* buffer to hold each line read from file */
        size_t n = 0;       /* line counter */
        FILE *fp;           /* file pointer */
    
        if (argc < 2 ) {    /* validate 1 argument given for filename */
            fprintf (stderr, "error: insufficient input,\n"
                             "usage: %s filename\n", argv[0]);
            return 1;
        }
    
        /* open file/validate file open for reading */
        if ((fp = fopen (argv[1], "r")) == NULL) {
            perror ("fopen-argv[1]");
            return 1;
        }
    

    Using fgets() and a buffer (e.g. a character array of MAXC, max characters), you can read and discard your first line. (*don't forget to validate the read):

        if (!fgets (buf, MAXC, fp)) {   /* read/discard 1st line */
            fputs ("error: EOF on read of first line.\n", stderr);
            return 1;
        }
    

    Now simply loop reading each subsequent line with fgets() into the same buffer and then pass that buffer to sscanf() for parsing the values you need from the line, e.g.

        while (fgets (buf, MAXC, fp)) { /* read all remaining lines */
            char date[MAXF], time[MAXF], prod[MAXF], unit[MAXF];
            double measure;
    
            if (sscanf (buf, "%s %s %s %lf %s", /* validate all 5 fields */
                        date, time, prod, &measure, unit) != 5) {
                fprintf (stderr, "error: invalid format, line: %zu\n", n + 1);
                continue;
            }
    

    (note: if the format of the line is bad, your read does not fail as it would with fscanf(). Here by reading with fgets(), you consume one-line at at time, regardless of format, and then use sscanf() to parse the values from the line. If the line format does not match your format-string, you simply discard the line and go read the next line.)

    Now you can do whatever you like with the values separated into date, time, prod, measure & unit. Here we will simply compare measure to see if it is 10.0 or greater up to 11.0 (non-inclusive) and subtract 10.0 from the value making the value 0.xxx where it was 10.xxx. You can simply output 0.0 if you like (up to you)

            /* do whatever you need with the separated values.
             * if measure is 10.xx, then make measure 0.xx
             */
            if (10.0 <= measure && measure < 11.0)
                printf ("measurement[%2zu]: %.3f   (was %.3f)\n",
                        n, measure - 10., measure);
            else
                printf ("measurement[%2zu]: %.3f\n", n, measure);
    
            n++;    /* increment line counter */
        }
    }
    

    That is about as simple an example as you want. The fundamentals of (1) read with fgets() and (2) parse with sscanf() can cover a wide range of input situations. You will use it over and over again. The reason to do so rather than using fscanf() directly is to prevent a format error of a single line causing a matching-failure where character extraction from the input-stream stops leaving the offending characters in the input-stream unread, just waiting to bite you again on your next attempted input.

    The full example is:

    #include <stdio.h>
    
    #define MAXC 1024       /* if you need a constant, #define one (or more) */
    #define MAXF   32
    
    int main (int argc, char **argv) {
    
        char buf[MAXC];     /* buffer to hold each line read from file */
        size_t n = 0;       /* line counter */
        FILE *fp;           /* file pointer */
    
        if (argc < 2 ) {    /* validate 1 argument given for filename */
            fprintf (stderr, "error: insufficient input,\n"
                             "usage: %s filename\n", argv[0]);
            return 1;
        }
    
        /* open file/validate file open for reading */
        if ((fp = fopen (argv[1], "r")) == NULL) {
            perror ("fopen-argv[1]");
            return 1;
        }
    
        if (!fgets (buf, MAXC, fp)) {   /* read/discard 1st line */
            fputs ("error: EOF on read of first line.\n", stderr);
            return 1;
        }
    
        while (fgets (buf, MAXC, fp)) { /* read all remaining lines */
            char date[MAXF], time[MAXF], prod[MAXF], unit[MAXF];
            double measure;
    
            if (sscanf (buf, "%s %s %s %lf %s", /* validate all 5 fields */
                        date, time, prod, &measure, unit) != 5) {
                fprintf (stderr, "error: invalid format, line: %zu\n", n + 1);
                continue;
            }
    
            /* do whatever you need with the separated values.
             * if measure is 10.xx, then make measure 0.xx
             */
            if (10.0 <= measure && measure < 11.0)
                printf ("measurement[%2zu]: %.3f   (was %.3f)\n",
                        n, measure - 10., measure);
            else
                printf ("measurement[%2zu]: %.3f\n", n, measure);
    
            n++;    /* increment line counter */
        }
    }
    

    Example Input File

    $ cat dat/data_timestamp.txt
    TimeDateStamp Product Measurement Unit
    2019-11-09 16:54    FS2012  0.344   SLPM
    2019-11-09 16:54    FS2012  0.344   SLPM
    2019-11-09 16:54    FS2012  0.344   SLPM
    2019-11-09 16:54    FS2012  0.344   SLPM
    2019-11-09 16:54    FS2012  0.136   SLPM
    2019-11-09 16:54    FS2012  0.136   SLPM
    2019-11-09 16:54    FS2012  0.136   SLPM
    2019-11-09 16:54    FS2012  0.136   SLPM
    2019-11-09 16:54    FS2012  0.047   SLPM
    2019-11-09 16:54    FS2012  0.047   SLPM
    2019-11-09 16:54    FS2012  0.047   SLPM
    2019-11-09 16:54    FS2012  0.047   SLPM
    2019-11-09 16:54    FS2012  1.991   SLPM
    2019-11-09 16:54    FS2012  1.991   SLPM
    2019-11-09 16:54    FS2012  1.991   SLPM
    2019-11-09 16:54    FS2012  10.0    SLPM
    2019-11-09 16:54    FS2012  10.661  SLPM
    2019-11-09 16:54    FS2012  10.991  SLPM
    2019-11-09 16:54    FS2012  11.0    SLPM
    

    Example Use/Output

    Below, I show where the 10 was reduced to 0:

    $ ./bin/read_data_timestamp dat/data_timestamp.txt
    measurement[ 0]: 0.344
    measurement[ 1]: 0.344
    measurement[ 2]: 0.344
    measurement[ 3]: 0.344
    measurement[ 4]: 0.136
    measurement[ 5]: 0.136
    measurement[ 6]: 0.136
    measurement[ 7]: 0.136
    measurement[ 8]: 0.047
    measurement[ 9]: 0.047
    measurement[10]: 0.047
    measurement[11]: 0.047
    measurement[12]: 1.991
    measurement[13]: 1.991
    measurement[14]: 1.991
    measurement[15]: 0.000   (was 10.000)
    measurement[16]: 0.661   (was 10.661)
    measurement[17]: 0.991   (was 10.991)
    measurement[18]: 11.000
    

    Look things over and let me know if this is close to what you need. I may still be misunderstanding what you are trying to achieve with 10 to 0, but just drop a comment below if I misunderstood and I'm happy to help further.

    Writing To Output File Taken As 2nd Argument To Program

    To write the adjusted Measurement value alone to an output file of your choosing, you can simply provide the output filename you want to use after your input filename on the command line and then open a file for output using argv[2] (your second command-line argument to main()) The changes are minimal. Just add another FILE* pointer ofp (for output file-pointer) and then open that file for writing:

        FILE *fp, *ofp;     /* file pointer, output file pointer */
    
        if (argc < 3 ) {    /* validate 2 arguments given for in/out filenames */
            fprintf (stderr, "error: insufficient input,\n"
                             "usage: %s filename outfilename\n", argv[0]);
            return 1;
        }
    
        /* open file/validate file open for reading */
        if ((fp = fopen (argv[1], "r")) == NULL) {
            perror ("fopen-argv[1]");
            return 1;
        }
    
        if ((ofp = fopen (argv[2], "w")) == NULL) {
            perror ("fopen-argv[2]");
            return 1;
        }
    

    Then just output the adjusted measurement using fprintf, e.g.

            if (10.0 <= measure && measure < 11.0)
                fprintf (ofp, "%.3f\n", measure - 10.);
            else
                fprintf (ofp, "%.3f\n", measure);
    

    (the rest of the program is exactly the same)

    #include <stdio.h>
    
    #define MAXC 1024       /* if you need a constant, #define one (or more) */
    #define MAXF   32
    
    int main (int argc, char **argv) {
    
        char buf[MAXC];     /* buffer to hold each line read from file */
        size_t n = 0;       /* line counter */
        FILE *fp, *ofp;     /* file pointer, output file pointer */
    
        if (argc < 3 ) {    /* validate 2 arguments given for in/out filenames */
            fprintf (stderr, "error: insufficient input,\n"
                             "usage: %s filename outfilename\n", argv[0]);
            return 1;
        }
    
        /* open file/validate file open for reading */
        if ((fp = fopen (argv[1], "r")) == NULL) {
            perror ("fopen-argv[1]");
            return 1;
        }
    
        if ((ofp = fopen (argv[2], "w")) == NULL) {
            perror ("fopen-argv[2]");
            return 1;
        }
    
        if (!fgets (buf, MAXC, fp)) {   /* read/discard 1st line */
            fputs ("error: EOF on read of first line.\n", stderr);
            return 1;
        }
    
        while (fgets (buf, MAXC, fp)) { /* read all remaining lines */
            char date[MAXF], time[MAXF], prod[MAXF], unit[MAXF];
            double measure;
    
            if (sscanf (buf, "%s %s %s %lf %s", /* validate all 5 fields */
                        date, time, prod, &measure, unit) != 5) {
                fprintf (stderr, "error: invalid format, line: %zu\n", n + 1);
                continue;
            }
    
            /* do whatever you need with the separated values.
             * if measure is 10.xx, then make measure 0.xx
             */
            if (10.0 <= measure && measure < 11.0)
                fprintf (ofp, "%.3f\n", measure - 10.);
            else
                fprintf (ofp, "%.3f\n", measure);
    
            n++;    /* increment line counter */
        }
    }
    

    If I then call my program with two-arguments (e.g. the input and output filenames) as follows:

    $ ./bin/read_data_timestamp2 dat/data_timestamp.txt dat/measure_val.txt
    

    I would read from my input file dat/data_timestamp.txt and write the results to my output file dat/measure_val.txt (you can use any filename you like for your output file, but your input would be Data.txt).

    Resulting OUtput File

    $ cat dat/measure_val.txt
    0.344
    0.344
    0.344
    0.344
    0.136
    0.136
    0.136
    0.136
    0.047
    0.047
    0.047
    0.047
    1.991
    1.991
    1.991
    0.000
    0.661
    0.991
    11.000
    

    Let me know if that clears it up.