how to read data from a file with space ignored? - c

I have this piece of program that I use to read data from file:
void baca(int *n)
{
FILE *f = fopen("namafile.txt", "r");
if (f)
{
while (fscanf(f, "%[^|]|%d|%[^\n]\n", mhs[*n].nama, &mhs[*n].umur, mhs[*n].hp)==3)
{
(*n)++;
}
}
fclose(f);
}
If I write the data in the file like this, then the program reads it correctly:
nko|20|9999
hotma|21|9982882
andi|30|212313
But when I add some spaces like this, somehow it doesn't read it correctly:
nko | 20 | 9999
hotma | 21 | 9982882
andi | 30 | 212313
Can someone give me some hint on what I should do ?

Add a space to the format string to specify where the input can have optional whitespace
fscanf(f, "%[^|] |%d | %[^\n]\n", ...)
// ^^^ ^^^^^ optional whitespace
The conversion "%d" already includes optional leading whitespace.
If your input strings can get messier in the future, you will do better with a separate parser instead of scanf().

Related

C - sscanf ignoring comma from csv file and reading the same piece of data twice

I am trying to read from a CSV file into struct. For some reason, the value for social security numbers is also reading the address and them the address is being read a second time into newBin.address. It looks like the sscanf is ignoring the comma that separates the socials and address when it reads the file but then does register it when it moves on reading the address. Any help is appreciated.
#include <stdio.h>
#include<string.h>
#include<stdlib.h>
#define STRSIZE 70
typedef struct BIN_DATA {
unsigned int user_number;
char name[32];
char social_security[10];
char address[32];
} BIN_DATA;
int main()
{
// Define variables.
FILE *in, *out;
char str[STRSIZE];
// New BIN.
BIN_DATA newBin;
// Open files.
in = fopen("updated.txt", "r");
// Check files.
if(in == NULL)
{
puts("Could not open file");
exit(0);
}
while(fgets(str, STRSIZE, in) != NULL)
{
memset(&newBin, '\0', sizeof(BIN_DATA));
sscanf(str, "%6u, %[^,], %[^,], %[^\n\r]", &newBin.user_number, newBin.name,\
newBin.social_security, newBin.address);
printf("%u. %s. %s. %s.\n", newBin.user_number, newBin.name,\
newBin.social_security, newBin.address);
}
return 0;
}
File being read:
289383,Estefana Lewey,591-82-1520,"9940 Ohio Drv, 85021"
930886,Burl Livermore,661-18-3839,"226 Amherst, 08330"
692777,Lannie Crisler,590-36-6612,"8143 Woods Drv, 20901"
636915,Zena Hoke,510-92-2741,"82 Roehampton St, 47905"
747793,Vicente Clevenger,233-46-1002,"9954 San Carlos St., 55016"
238335,Lidia Janes,512-92-7402,"348 Depot Ave, 29576"
885386,Claire Paladino,376-74-3432,"587 Front Ave, 32703"
760492,Leland Stillson,576-55-8588,"9793 Boston Lane, 08610"
516649,Wes Althouse,002-58-0518,"8597 Annadale Drive, 06514"
641421,Nadia Gard,048-14-6428,"218 George Street, 29150"
As mentioned in the comments, the social_security member does not allocate enough space to hold the data you're reading. It needs to be at least 12 to hold the SSN as written with a terminator at the end.
As for the format string you use with sscanf(), it's nearly correct. However, you'll want to bound the maximum string length to match what you have storage for, so for example with name of 32 you should limit it to 31 characters saving one at the end for the terminator.
I changed the social_security field to char social_security[12]; and then changed the format string to sscanf to be the following:
"%6u, %31[^,], %11[^,], %31[^\n\r]"
I was able to run the modified code with the sample input file to get the output you described. You can try it too at the link:
Runnable code

How to read data from txt file>

I have a little problem with reading data from file.
I need to read the name, lastname and phone number.
But the data is separated by '|'.
file e.g.
Matthew | McConaughey | 684299275
Humphrey | Bogart | 204050673
Mary | Tyler Moore | 503462885
Loretta | Young | 416211713
I wrote this function
char name[20];
char lastname[40];
int number;
while(!feof(plik)){
int hpl=fscanf(filename, "%s | %s | %d", name, lastname, &number);
}
I have problem when in the file are two-member lastname like 'Tyler Moore', then fscanf return 2
I don't know how I can read them
That is possible to use one fscanf() function ?
It is because, scanf family functions read until space. You can use fgets to get whole line, and then parse it using function multi_tok function that is shown here: https://stackoverflow.com/a/29789623/8842262

C Linux fscanf not reading all of line

I'm working with some code written by someone else to scan key value string pairs from a config file. The code is:
void readProfile(char * profileName) {
FILE *f;
int i=0;
f = fopen(profileName, "r");
if (NULL != f) {
while (fscanf(f, "%s%s", &pvtProperties[i].key[0],
&pvtProperties[i].value[0]) == 2) {
i++;
}
fclose(f);
}
numberOfProperties = i;
setCurrentProfileName(profileName);
}
However when reading this plaintext config file below, it has a problem with the 4th line:, the value is truncated to "https://dev.xxxx.com:58443/services/PvtTransferSer". Each line of the config file is separated by \r\n. From that point on the reading of the rest of the file is messed up, values becoming keys etc. Why is this happening? The keys and values are char arrays of 80 chars each.
Config file:
PASSWORD xxxx
REMOTE_UPDATES_ENABLE 1
REMOTE_DIAGNOSTICS_ENABLE 1
PVT_TRANSFER_WS_ADDRESS https://www.xxxx.com:58443/services/PvtTransferService
PVT_DIAGNOSTIC_WS_ADDRESS https://www.xxxx.com:58443/services/PvtDiagnosticService
PVT_UPDATE_WS_ADDRESS https://www.xxxx.com:58443/services/PvtUpdateService
PVT_ADJUSTMENT_WS_ADDRESS https://www.xxxx.com:58443/services/PvtAdjustmentService
DAILY_RESTART_ENABLE 1
HOUR_PAST_MIDNIGHT_FOR_RESTART 7
MAX_RESTART_RANDOMIZATION_SECONDS 30
MINIMUM_UPTIME_SECONDS_BETWEEN_RESTARTS 7200
CLEAR_CACHE_ON_RESTART_ENABLE 0
MINIMUM_SECONDS_BETWEEN_REMOTE_UPDATE_CHECKS 3600
SECONDS_BETWEEN_CONTROLLER_CONFIGURATION_CHECKS 300
CONNECTIVITY_LOSS_DETECTION_ENABLE 1
SMART_COMM_ENABLE 1
TIME_SYNC_ENABLE 1
FACTORY_RESET_ENABLE 1
CM_POLL_PROTOCOL http
You can solve your phase issue by using fgets to pull a line in at a time from the file; then sscanf to parse that line buffer for each record.

Editing a line in a text file using temp file C

I am trying to edit a line in a textfile but i have an unexpected behavior while i am editing the file. What i want to do is adjust a specific line (points : 100) of a text that looks like. In the function i pass arguments by value the new coins to be adjusted and the offset of the file with ftell->user_point. What i get as an output is weird. I try to copy the rest of the file to a temp,with an edited line, and then copy it back to the original file from the point that i copied to temp.(thats the user_point offset with ftell).
Here is the original fie with entries like that:
...
_______________________________________
nickname : geo
password : cuvctq
Name : george
Surname : papas
points : 100
participated :
past draws : 0
Chosen No. :
future draws : 0
Registered : Sun Feb 05 19:23:50 2012
...
What i get after 2nd edit run is:
...
_______________________________________
nickname : geo
password : cuvctq
Name : george
Surname : papaspoints : 98
participated :
past draws : 0
Chosen No. :
future draws : 0
Registered : Sun Feb 05 19:23:50 2012
...
At the end of the text i get one extra \n after i edit the
file whch is something i dont want :/
and so further edit will spoil the text...
I also get an EXTRA \n at the end of the line which, at least what i think so, is due to "r+" mode which is something that i also dont want...
void coins_adjust(int coins_new,int user_point)
{
int lines,i,ln_point_copy;
char buffer[50],buff_copied[50];
FILE *lottary,*temp;
memset(buff_copied,'\0',sizeof(char)*50);
lottary=fopen("customers.txt","r");
temp=fopen("temp.txt","w");
fseek(lottary,user_point,SEEK_SET);
for (lines=0;lines<5;lines++)
{
memset(buffer,'\0',sizeof(char)*50);
if (lines==5)
ln_point_copy=ftell(lottary); //from TEMP to CUSTOMERS
fgets (buffer ,50 , lottary);
}
coins_new+=atoi(buffer+15);
strncpy(buff_copied,buffer,15); //copy 15 chars and fill with null
memset(buffer,'\0',sizeof(char)*50);
itoa (coins_new,buffer,10); //fix the new line to be entered
strcat(buff_copied,buffer); //the edited line is as it is supposed
strcat(buff_copied,"\n"); //to be with \n at the end.
puts(buff_copied);
printf("%s",buff_copied);fflush(stdout);
fprintf(temp,"%s",buff_copied);
for(i=getc(lottary); i!=EOF; i=getc(lottary)) //copy to temp
{
putc(i, temp);
}
fclose(lottary);
fclose(temp);
temp=fopen("temp.txt","r");
lottary=fopen("customers.txt","r+");
fseek(lottary,ln_point_copy,SEEK_SET);
for(i=getc(temp); i!=EOF; i=getc(temp)) //copy until eof
{
putc(i, lottary);
}
fclose(lottary);fclose(temp);
}
I have debugged the program and everything seems to work at least on what values are passed to the arrays where i store the line chars but i cant see why it ignores the \n of the previous line when i try to copy it back to the original... There seems to be a \r char that i cant get rid of while i copy back to the original...
Thanks in advance.
I was more thinking about something like this:
void change_points(int new_points)
{
FILE *input = fopen("customers.txt", "r");
FILE *output = fopen("temp.txt", "w");
char buffer[256];
while (fgets(buffer, sizeof(buffer), input))
{
/* Look for the correct line */
/* Can also use e.g. "if (strncmp(buffer, "points", 6) == 0)"
* if it's at the start of the line
*/
if (strstr(buffer, "points") != NULL)
{
int old_points;
sscanf(buffer, "%*s : %d ", &old_points);
/* Format how you like it */
fprintf(output, "%-13s: %d\n", "points", new_points + old_points);
}
else
fputs(buffer, output);
}
fclose(output);
fclose(input);
/* The file "temp.txt" now contains the modifeed text */
/* Copy either using "fgets"/"fputs", or using "fread"/"fwrite" */
input = fopen("temp.txt", "r");
output = fopen("customers.txt", "w");
while (fgets(buffer, sizeof(buffer), input))
fputs(buffer, output);
fclose(output);
fclose(input);
}
It's shorter, simpler, maybe more effective (looping over line-by-line instead of char-by-char), and the line you are looking for can be anywhere in the file without you knowing its exact position.

C - Read in file according to a format

I am trying to read a file in a specific file format in c.
the file contains some data items. every data item is seprated by a flag.
the file should look look like this:
file-header: "FIL0"
file-id: 0x1020304
flag : 0|1 : uint8_t
length : uint32_t
char[length] : int utf-8
so its: [File-Header] [FileID] [Flag | Length | Data ] [Flag | Length | Data] ...
--> "FIL0" | 0xFFFFFF | 0 or 1 | Data as char[] | 0 or 1 | ... (next data item) ....
My Problem occurs when reading in the file. My idea is to open the file and scan through it using some sscanf-magic.
FILE *fp;
fp = fopen("data.dat". "r");
/* scan file for data components */
while (fgets(buffer, sizeof buffer, fp) != NULL) /* read in file */
{
/* scan for sequence */
if (sscanf(buffer, "%5s", fil0_header) == 1) /* if the "FIL0" header is found */
{
printf("FIL0-header found: %s\n", buffer);
// proceed and scan for [FLAG] [LENGTH] [DATA]
// sscanf()
if (sscanf(buffer, "%u", node) == 1)
{
// doesnt seem to work
}
// read in length of string and extract stringdata
else
{
printf("FIL0-Header not found, found instead: %s\n", buffer);
// do something
}
}
My problem that I have a hard time with my buffer and the varying data types in the file.
The comparision of fil0-header works alright, but:
how to read in the next hexadeciaml number (sscanf using %D)
how scan for the flag which is 1 byte
how to extract the length which is 4 bytes
A problem is, that the check for the flag starts at the beginning of the buffer.
but the pointer should be moved on, after the FIL0-header is found.
I'd be gratefull for any help!
Please help me to find the proper sscanf() -calls:
and want to read it in and retrieve the single parts of my file:
On single [File-Header]
and many {[FileID] [Flag | Length | Data ]} {...} items
well you could just read the file per byte using
line[0] = (char) fgetc(fp);
line[1] = (char) fgetc(fp);
and so on or leave out the cast to retrieve an int-value... should do the trick to do an easy right to left scan of the file (or line - as you say there arent any line breaks)...
You probably could use some standard parsing techniques, for instance have a lexer and a recursive parser. You should define your input syntax more in details. You could perhaps use parser generators (but it might be overkill for your simple example) like ANTLR ...
I suggest you to read some good textbook on parsing (& compiling), it will learn you a lot of useful stuff.

Resources