I've tried multiple stuff as reading new lines after checking if that columns is "General" but still does not work at all. It is an csv file and it would be lines with commas after each fgets and i need a specific column with it's data.
Here's my code:
char fi[1024];
while(!feof(CsvFile)){
//Read
fgets(fi, 1024, CsvFile);
if(strstr(fi, "General") == 0){
fscanf(CsvFile, "%[^\n]s", fi);
printf("%s", fi);
}
fgetc(CsvFile);
}
It does not print what i want.
Reading a CSV file is much more complicated than you assumed (see https://www.rfc-editor.org/rfc/rfc4180). You must take all kind of rules into account. For instance, if a cell contains a comma, the content must be surrounded by ".
However, you can implement a simplified version which assumes:
a CSV file is made of lines;
a line is MAX_LINE characters, at most;
a line is made of cells;
a cell ends with comma or new-line;
a cell contains anything but comma or new-line.
The code below reads one line at a time and then uses strtok to split the line into cells.
Welcome to SO and good luck!
#include <stdio.h>
#include <string.h>
#define MAX_LINE 1024
int main( int argc, char* argv[] )
{
//
FILE* fp = fopen( "c:\\temp\\so.txt", "r" );
if ( !fp )
{
printf( "could not open file" );
return -1;
}
//
char line[ MAX_LINE + 1 ];
while ( fgets( line, sizeof( line ) / sizeof( *line ), fp ) ) // get a line
{
int col_idx = 0;
const char* sep = "\r\n,"; // cells are separated by a comma or a new line
char* cell = strtok( line, sep ); // find first cell
while ( cell )
{
// your processing code goes here
cell = strtok( NULL, sep ); // next cell
col_idx++;
}
}
return 0;
}
Related
I am writing a text file parser in C.
I would like to read each line of a text file using fgets, except for the very last line, which I would like to skip.
Also, there is no telling how many characters will be in the file or in the last line, but assume my parser only cares about the first LINEMAXLEN characters in each line.
Currently, the only way I can think to do this is by running two loops, something like the following:
char line[ LINEMAXLEN+1u ];
unsigned int nlines;
unsigned int i;
nlines = 0u;
while ( fgets (line, LINEMAXLEN, file) != NULL )
nlines += 1u;
i = 0u;
while ( fgets (line, LINEMAXLEN, file) != NULL ) {
if ( i >= nlines - 1u )
break;
//...parse the line
i += 1u;
}
But surely, there's got to be a smarter way to do it in only one loop, no?
Instead of using two loops, it would be more efficient to always read two lines in advance and to only process a line once the next line has been sucessfully read. That way, the last line will not be processed.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define LINEMAXLEN 30
//forward function declarations
void process_line( const char *line );
bool read_start_of_line_and_discard_rest( char buffer[], int buffer_size, FILE *fp );
int main( void )
{
FILE *fp;
char lines[2][LINEMAXLEN];
//This index specifies which index in the array "lines"
//represents the newest line. The other index is the
//index of the previous line.
int newest_index = 0;
//attempt to open file
fp = fopen( "input.txt", "r" );
if ( fp == NULL )
{
fprintf( stderr, "Error opening file!\n" );
exit( EXIT_FAILURE );
}
//read first line
if ( !read_start_of_line_and_discard_rest( lines[newest_index], LINEMAXLEN, fp ) )
{
fprintf( stderr, "Error reading first line!\n" );
exit( EXIT_FAILURE );
}
//process one line per loop iteration
for (;;)
{
//swap the index, so that the newest line is now the
//previous line
newest_index = !newest_index;
//read the new line
if ( !read_start_of_line_and_discard_rest( lines[newest_index], LINEMAXLEN, fp ) )
{
//we have reached end-of-file, so we don't process the
//previous line, because that line is the last line
break;
}
//since reading in a new line succeeded, we can be sure that
//the previous line is not the last line, so we can process
//the previous line
//process the previous line
process_line( lines[!newest_index] );
}
//cleanup
fclose( fp );
}
//This function will process a line after it has been read
//from the input file. For now, it will only print it.
void process_line( const char *line )
{
printf( "Processing line: %s\n", line );
}
//This function will read exactly one line of input and remove the
//newline character, if it exists. On success, it will return true.
//If this function is unable to read any further lines due to
//end-of-file, it returns false. If it fails for any other reason, it
//will not return, but will print an error message and call "exit"
//instead.
//If the line is too long to fit in the buffer, it will discard
//the rest of the line and report success.
bool read_start_of_line_and_discard_rest( char buffer[], int buffer_size, FILE *fp )
{
char *p;
//attempt to read one line from the stream
if ( fgets( buffer, buffer_size, fp ) == NULL )
{
if ( ferror( fp ) )
{
fprintf( stderr, "Input error!\n" );
exit( EXIT_FAILURE );
}
return false;
}
//determine whether line was too long for input buffer
p = strchr( buffer, '\n' );
if ( p == NULL )
{
int c;
//discard remainder of line
do
{
c = getchar();
} while ( c != EOF && c != '\n' );
}
else
{
//remove newline character by overwriting it with a null
//character
*p = '\0';
}
return true;
}
For the input
This is line1.
This is line2 which has an additional length longer than 30 characters.
This is line3.
This is line4.
this program has the following output:
Processing line: This is line1.
Processing line: This is line2 which has an ad
Processing line: This is line3.
As you can see, all lines except the last line are being processed, and only the first LINEMAXLEN-1 (30-1 in my example) characters of each line are being processed/stored. The remaining characters are being discarded.
Only LINEMAXLEN-1 instead of LINEMAXLEN characters from each line are being processed/stored because one character is required to store the terminating null character.
This is quite simple to do in a single loop if we use alternating buffers [as others have mentioned].
In the loop below we read a line into the "current" buffer. If not the first line, we process the previous line in the "other" buffer.
By alternating the index into a buffer pool of two buffers, we avoid unnecessary copying.
This introduces a delay in the processing of the buffer. On the last iteration, the last line will be in the current buffer, but it will not be processed.
#define LINEMAXLEN 1000 // line length of buffer
#define NBUF 2 // number of buffers
char lines[NBUF][LINEMAXLEN]; // buffer pool
int previdx = -1; // index of bufs for _previous_ line
int curidx = 0; // index of bufs for _current_ line
char *buf; // pointer to line buffer to process
// read all lines into alternating line buffers
for (; fgets(lines[curidx],LINEMAXLEN,stdin) != NULL;
previdx = curidx, curidx = (curidx + 1) % NBUF) {
// process _previous_ line ...
if (previdx >= 0) {
buf = lines[previdx];
// process line ...
}
}
fgets() will not modify the buffer at all when it reaches EOF, so just read lines until fgets() returns NULL. The last line read will be retained:
#include <stdio.h>
int main( int argc, char **argv )
{
char line[ 1024 ];
FILE *f = fopen( argv[ 1 ], "r" );
if ( NULL == f )
{
return( 1 );
}
for ( ;; )
{
char *p = fgets( line, sizeof( line ), f );
if ( NULL == p )
{
break;
}
}
printf( "last line: %s\n", line );
return( 0 );
}
This relies on the required behavior of fgets():
The fgets function returns s if successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned.
Robust code should check for errors with ferror().
Working that into your text processing is left as an exercise... ;-)
I'm given a text file containing information about a game world and it's collision data in this format.
Width 5
Height 5
10001
11000
11100
11111
11111
To store the data, I'm given
static int BINARY_MAP_WIDTH;
static int BINARY_MAP_HEIGHT;
and
static int **MapData; // Dynamic array of map data
My FileIO knowldege doesn't go much beyond reading in strings from a file line by line.
So far I have this very roundabout way of reading in just the first two lines.
FILE *Data;
int line = 1; // line number that we're on
Data = fopen(FileName, "rt");
if (!Data)
return 0;
if (Data)
{
while (!feof(Data))
{
if (line == 1)
fscanf(Data, "%*[^0-9]%d%n", &BINARY_MAP_WIDTH);
if (line == 2)
fscanf(Data, "%*[^0-9]%d%n", &BINARY_MAP_HEIGHT);
if (line > 2)
break;
line++;
}
}
And to be quite honest, I'm not entirely sure why it's working, but I am getting the correct values into the variables.
I know how to set up the dynamic array, at this point my issue is with reading in the correct values.
I'm not sure where to go from here.
Here's a couple things you need to know about fscanf
fscanf will consume as many bytes as necessary to perform the
requested conversions and will update the file pointer accordingly.
The next call to fscanf will start at the location in the file
where the previous fscanf ended.
fscanf returns the number of successful conversions, so you
should verify that the return value is equal to the number of
conversions requested.
So here's how I would rewrite the code you have so far
#include <stdio.h>
static int mapWidth;
static int mapHeight;
int readFromFile( char *name )
{
FILE *fp;
int good = 1;
if ( (fp = fopen(name, "r")) == NULL )
return 0;
if ( fscanf(fp, "%*[^0-9]%d", &mapWidth) != 1 )
good = 0;
if ( fscanf(fp, "%*[^0-9]%d", &mapHeight) != 1 )
good = 0;
if ( good )
{
// the code to read the rest of the file goes here
}
fclose( fp );
return good;
}
int main( void )
{
if ( readFromFile( "input.txt" ) )
printf( "%d %d\n", mapWidth, mapHeight );
else
printf( "readFromFile failed\n" );
}
The next step is to figure out
how to allocate memory for MapData based on the width and height
how to read the rest of the lines in a loop, e.g. using fgets or fscanf(..."%s"...)
how to parse those lines to fill in the MapData
I am trying to read strings from a file separated by commas, and want to display and save the result into a particular format (which looks like a JSON format) during output.
I managed to read and display data from a file but failed to dynamically display it in a format which looks like the example below. Instead, it just displays the entire string in one line before ending.
e.g.
Contents of the file:
Distance, 50km, Time, 2 hrs, Date, 1 Jan 2015, etc.
Desired output result:
{"Distance":"50km"}
{"Time":"2hrs"}
{"Date":"1 Jan 2015"}
Actual Output
{" Entire contents from the file " : " nothing appears here "}
I've commented out the lines that deals with reading the file contents until it finds a comma, and where it prints the result in the desired format as those lines didn't work correctly.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ( int argc, char *argv[] )
{
if ( argc != 2 )
{ printf( "Insert filename you wish to open\n Eg: %s filename\n\n", argv[0] );
}
else
{
FILE *file = fopen( argv[1], "r" );
if ( file == 0 )
{
printf( "There was an error opening the file\n\n" );
}
else
{
char a,b;
while ( ( a = fgetc( file ) ) != EOF )
{
printf( "%c", a,b );
//fscanf(file,"%[^,]",a);/* Read data until a comma is detected, */
// printf("\nData from file:\n{\"%s\" : \"%s\"}\n\n",a,b); /* Display results into {"A":"B"} format */
}
fclose( file );
}
}
return 0;
}
Use this code:
char a[50], b[50];
while(1 == fscanf(file," %[^,]",a) ) /* Read data until a comma is detected, */
{
fgetc( file ); // Ignore , character
fscanf(file," %[^,]",b); /* Read data until a comma is detected, */
fgetc( file ); // Ignore , character
printf("{\"%s\":\"%s\"}\n",a,b); /* Display results into {"A":"B"} format */
}
Live demo here
Note the extra space before format in fscanf
The algorithm to read is:
while( is reading [a] succesful )
{
ignore comma
read [b]
ignore comma
print {"a": "b"}
}
I am trying to create a spell checking program that takes an input file and makes sure each word is correct by searching through a dictionary file. The problem i am facing is that when i try to take each word seperated by spaces from the input file and put it into a char [] the words with " for some reason print
H0
i1
c0
h1
r2
i3
s4
!5
â0
1
2
h3
o4
w5
w6
â7
8
9
a0
r1
42
e3
y0
o1
u2
.3
the integers are my index
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "dict.h"
int main(int argc, char *argv[] ) {
FILE *fdict,*input;
int i;
char ch;
/* the biggest posible word is 30 plus a possible of two " or ' characters and the null character. so the limit of the array is 33*/
char norm[33];
if ( argc < 3 ) /* argc should be 3 for correct execution*/
{
fprintf(stderr,"1 or 2 Files were missing.");
exit(1);
}
if ( argc > 3 ){
fprintf(stderr,"too many Arguments");
exit(1);
}
/* We assume argv[1] and agrv[2] are filenames to open*/
fdict = fopen( argv[1], "r" );/* file pointer for the dictionary file*/
input = fopen( argv[2], "r" );/*file pointer for the input file*/
/* fopen returns NULL on failure */
if ( fdict == NULL ){
fprintf(stderr,"Could not open file: %s\n", argv[1] );/*checks to make sure the dictionary file can be opened*/
exit(1);
}
if ( input == NULL ){
fprintf(stderr,"Could not open file: %s\n", argv[2] );/*checks to make sure the input file can be opened*/
exit(1);
}
/* Read one character at a time from file, stopping at EOF, which
indicates the end of the file. Note that the idiom of "assign
to a variable, check the value" used below works because
the assignment statement evaluates to the value assigned. */
while ( ( ch = fgetc( input ) ) != EOF ) {
char word[33] = "";/* resets the array*/
for ( i = 0; !isspace( ch ) ; i++ ){
word[i] = ch;
printf("%c%d\n",ch,i);/* checking to see what is wrong with the index*/
ch = fgetc( input );
}
}
fclose( fdict );
fclose( input );
return 0;
}
my input looks like:
Hi chris! “howw” are you.
" is not the same as “ nor ”. (3 different quote marks.) Based on different encodings, these 3 characters use various sequences of char to represent them yet code only prints one char at a time.
Suggest just using the simpe quote mark ".
A simple or programmer's text editor would do. Avoid a word processor that may bring in non-ASCII quote marks until your code is ready for that (#n.m.)
#include <stdio.h>
#include <stdlib.h>
int main ( int argc, char *argv[] )
{
//sets the number of lines ot be read
char strline[10000];
// checks to see that there are only 2 entries in the argv by checking in argc
if ( argc != 2 )
{
printf( "ERROR. Enter a file name\n", argv[0] );
}
else
{
//opens the file which was entered by the user as read only
FILE *infile = fopen( argv[1], "r");
// covers a miss spelling of a file name or file doesn't exist
if ( infile == 0 )
{
printf( "ERROR. Did you make a mistake in the spelling of the file or the File entered doesn't exist\n" );
}
else
{
// File exists read lines, while not at the end of the file
while (!feof(infile))
{
//Get next line to be printed up to 126 characters per a line
if(fgets(strline, 126, infile))
{
//print the current line (stored in strline)
printf("%s",strline);
}
}
//closes the file
fclose( infile );
return 0;
}
}
}
On the 6th line (comment above) I have stated this is the maximum amount of lines the program can read. I was informed yesterday that this isn't the case.
Can someone explain to me what the code line actually means?
char strline[10000];
So from what people have being saying what setting it to 128 make more snese (126 for fgets and some room)
char strline[10000]; neans you have allocated a buffer that is 10,000 bytes long:
+--------------...-+
strline -> | 10000 |
+--------------...-+
if you wanted to allocate for 10,000 lines instead you would need something like this:
char* strline[10000]; // array of 10,000 pointers to strings
accessing lines would be to assign to each entry in the array
strline[0]
strline[1]
...
strline[10000]
like when a line is read you would need to allocate a buffer for the line and then point to it from strline
char* line = malloc( linelength + 1 );
fgets( line, linelength, fp );
strline[0] = line;
+-------+
strline[0] -> | line |
+-------+