detect if a line is match to a format - in C - c

I have a file and I need to check if its lines are in the following format:
name: name1,name2,name3,name4 ...
(some string, followed by ":", then a single space and after that strings separated by ",").
I tried doing it with the following code:
int result =0;
do
{
result =sscanf(rest,"%[^:]: %s%s", p1,p2,p3);
if(result==3)
{
printf("invalid!");
fclose(fpointer);
return -1;
}
}while (fgets(rest ,LINE , fpointer) != NULL);
this works good for lines like: name: name1, name2 (with space between name1, and name2).
but it fails with the following line:
name : name1,name2
I want to somehow tell sscanf not to avoid this white space before the ":".
could someone see how ?
Thanks for helping!

This works for me:
result = sscanf(rest,"%[^*:]: %[^,],%s", p1, p2, p3);
Notice the * is used to consume the space (if any).

Related

Inserting word from a text file into a tree in C

I have been encountering a weird problem for the past 2 days and I can't get to solve it yet. I am trying to get words from 2 texts files and add those words to a tree. The methods I choose to get the words are refereed here:
Splitting a text file into words in C.
The function that I use to insert words into a tree is the following:
void InsertWord(typosWords Words, char * w)
{
int error ;
DataType x ;
x.word = w ;
printf(" Trying to insert word : %s \n",x.word );
Tree_Insert(&(Words->WordsRoot),x, &error) ;
if (error)
{
printf("Error Occured \n");
}
}
As mentioned in the link posted , when I am trying to import the words from a text file into the tree , I am getting "Error Occured". For once again the function:
the text file :
a
aaah
aaahh
char this_word[15];
while (fscanf(wordlist, "%14s", this_word) == 1)
{
printf("Latest word that was read: '%s'\n", this_word);
InsertWord(W,this_word);
}
But when I am inserting the exact same words with the following way , it works just fine.
for (i = 0 ; i <=2 ; i++)
{
if (i==0)
InsertWord(W,"a");
if (i==1)
InsertWord(W,"aaah");
if (i==2)
InsertWord(W,"aaahh");
}
That proves the tree's functions works fine , but I can't understand what's happening then.I am debugging for straight 2 days and still can't figure it. Any ideas ?
When you read the words using
char this_word[15];
while (fscanf(wordlist, "%14s", this_word) == 1)
{
printf("Latest word that was read: '%s'\n", this_word);
InsertWord(W,this_word);
}
you are always reusing the same memory buffer for the strings. This means when you do
x.word = w ;
you are ALWAYS storing the SAME address. And every read redefine ALL already stored words, basically corrupting the data structure.
Try changing the char this_word[15]; to char *this_word; and placing a this_word = malloc(15);in the beggining of thewhile` loop instead, making it allocate a new buffer for each iteration. So looking like
char *this_word;
while (fscanf(wordlist, "%14s", this_word) == 1)
{
this_word = malloc(15);
printf("Latest word that was read: '%s'\n", this_word);
InsertWord(W,this_word);
}
As suggested by Michael Walz a strdup(3) also solves the immediate problem.
Of course you will also have do free up the .word elements when finished with the tree.
Seems like the problem was in the assignment of the strings.Strdup seemed to solve the problem !

Checking for a blank line in C - Regex

Goal:
Find if a string contains a blank line. Whether it be '\n\n',
'\r\n\r\n', '\r\n\n', '\n\r\n'
Issues:
I don't think my current regex for finding '\n\n' is right. This is my first time really using regex outside of simple use of * when removing files in command line.
Is it possible to check for all of these cases (listed above) in one regex? or do I have to do 4 seperate calls to compile_regex?
Code:
int checkForBlankLine(char *reader) {
regex_t r;
compile_regex(&r, "*\n\n");
match_regex(&r, reader);
return 0;
}
void compile_regex(regex_t *r, char *matchText) {
int status;
regcomp(r, matchText, 0);
}
int match_regex(regex_t *r, char *reader) {
regmatch_t match[1];
int nomatch = regexec(r, reader, 1, match, 0);
if (nomatch) {
printf("No matches.\n");
} else {
printf("MATCH!\n");
}
return 0;
}
Notes:
I only need to worry about finding one blank line, that's why my regmatch_t match[1] is only one item long
reader is the char array containing the text I am checking for a blank line.
I have seen other examples and tried to base the code off of those examples, but I still seem to be missing something.
Thank you kindly for the help/advice.
If anything needs to be clarified please let me know.
It seems that you have to compile the regex as extended:
regcomp(&re, "\r?\n\r?\n", REG_EXTENDED);
The first atom, \r? is probably unnecessary, because it doesn't add to the blank-line condition if you don't capture the result.
In the above, blank line really means empty line. If you want blank line to mean a line that has no characters except for white space, you can use:
regcomp(&re, "\r?\n[ \t]*\r?\n", REG_EXTENDED);
(I don't think you can use the space character pattern, \s here instead of [ \t], because that would include carriage return and new-line.)
As others have already hinted at, the "simple use of * in the command line` is not a regular expression. This wildcard-matching is called file globbing and has different semantics.
Check what the * in a regex means. It's not like the wildcard "anything" in the command line. The * means that the previous component can appear any amount of times. The wildcard in regex is the .. So if you want to say match anything you can do .*, which would be anything, any amount of times.
So in your case you can do .*\n\n.* which would match anything that has \n\n.
Finally, you can use or in a regex and ( ) to group stuff. So you can do something like .*(\n\n|\r\n\r\n).* And that would match anything that has a \n\n or a \r\n\r\n.
Hope that helps.
Rather than looking for only \r or \n, look for not \r or \n?
Your regex would simply be
'[^\r\n]'
and a match result of false indicates a blank line to your specification.

How to read data from a text file

How do I read input from my text file? The input file is several lines long, and each line is of the format city city distance where there are two cities and the distance between them.
I have tried several things to read the input, but unfortunately those did not work. I need
to parse the individual values on each line. (Each line consists of 2 city names and the distance between them.) Any help would be appreciated.
data = fopen(argv[1],"r");
while(!EOF){
while(1){
c=fgetc(data);
inname=(char**)malloc(sizeof(char*));
if(c==' ')
mode++;
else if(c=='\n'){mode=0;
break;}
else {
switch(mode%3){
case 0;
for(i=0;fgetc(data)!=' ';i++){
if(inname[count]!=NULL) {count++;inname=(char**)malloc(sizeof(char*));}
inname[count][i]=fgetc(data);}
break;
case 1;
if(inname[count]!=NULL){ count++;inname=(char**)malloc(sizeof(char*));}
for(i=0;fgetc(data)!=' ';i++){
inname[count][i]=fgetc(data);}
break;
/*case 2;for(i=0;fgetc(data)!='\n';i++){
dist[say]=atoi(str);}}}*/
}}}count++;}
`
I think you should look into fscanf for reading formatted input like this.
To read a line containing two strings and an int, you would have something like:
fscanf(data, "%s %s %d", &city1, &city2, &distance);
To read multiple lines until EOF, your code should be of the following form:
while(fscanf(data, "%s %s %d", &city1, &city2, &distance)!=EOF) {
/* rest of your logic here */
}

Creating a terminal menu with a challenge

What I wont to do is to create a terminal menu that takes various types of arguments and place it in a array param. Under is the code: Here is some trouble that I have and cant find a good solution for.
if i just type 'list' I will get Not a valid command, I have to type “list “ (list and space).
Menu choice new should be like this: new “My name is hello”. param[0] = new and param[1] = My name is hello , (sow I can create a message with spaces).
How can I accomplish this?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
int menu()
{
printf(">");
char line[LINE_MAX];
int i = 0;
char *param[4];
while(fgets(line, LINE_MAX, stdin) != NULL) {
param[i++] = strtok(line, " \n");
if(param[0] != NULL) {
char *argument;
while((argument = strtok(NULL, "\n")) != NULL) {
param[i++] = argument;
}
}
if(strcmp(param[0], "new") == 0) {
//new(param[1]);
menu();
} else if(strcmp(param[0], "list") == 0) {
//list();
menu();
} else {
printf("Not a valid command.\n\n");
menu();
}
}
return 0;
}
You're delimiting on " ".
fgets reads the ENTER.
So, when you type "listENTER" and tokenise at spaces you get one token, namely "listENTER". Later you compare with "list" and, of course, it doesn't match.
Try
strtok(line, " \n"); /* maybe include tabs too? */
PS. Why are you calling menu recursively? You already have a while in the function ...
Your problem is param[i++] = strtok(line, " "); will only split on space, not on \n (newline). Try adding this to your array of delimeters.
Oh, and congratulations for some decent looking code that's clean and well formatted. A pleasant change.
I'm not sure if this causes your problem but these lines
/*new(param[1]);
/*list();
Start a comment that is never terminated.
If you want one line comments you can use:
// comment
(atleast in C++ and from C99 on)
But comments starting with /*must be ended with a */and not nested:
/* comment */
/* also multi line
allowed */
Since you start a comment in a comment your compiler should have emmited a warning, actually this shouldn't compile at all.
The reason you need to type "list " is that your first strtok tokenizes until a space character, so you need to enter one in this case. Try allowing both '\n' and space as separators, i.e. replace the second parameter of strtok with " \n".
As for quotes, you need to re-combine parameters starting from the one beginning with a quote to the one ending with one by replacing the characters in between them with spaces. Or do away with strtok and parse by manually iterating through the characters in line.

Why does my program read an extra structure?

I'm making a small console-based rpg, to brush up on my programming skills.
I am using structures to store character data. Things like their HP, Strength, perhaps Inventory down the road. One of the key things I need to be able to do is load and save characters. Which means reading and saving structures.
Right now I'm just saving and loading a structure with first name and last name, and attempting to read it properly.
Here is my code for creating a character:
void createCharacter()
{
char namebuf[20];
printf("First Name:");
if (NULL != fgets(namebuf, 20, stdin))
{
char *nlptr = strchr(namebuf, '\n');
if (nlptr) *nlptr = '\0';
}
strcpy(party[nMember].fname,namebuf);
printf("Last Name:");
if (NULL != fgets(namebuf, 20, stdin))
{
char *nlptr = strchr(namebuf, '\n');
if (nlptr) *nlptr = '\0';
}
strcpy(party[nMember].lname,namebuf);
/*Character created, now save */
saveCharacter(party[nMember]);
printf("\n\n");
loadCharacter();
}
And here is the saveCharacter function:
void saveCharacter(character party)
{
FILE *fp;
fp = fopen("data","a");
fwrite(&party,sizeof(party),1,fp);
fclose(fp);
}
and the loadCharacter function
void loadCharacter()
{
FILE *fp;
character tempParty[50];
int loop = 0;
int count = 1;
int read = 2;
fp= fopen("data","r");
while(read != 0)
{
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
loop++;
count++;
}
fclose(fp);
}
So the expected result of the program is that I input a name and last name such as 'John Doe', and it gets appended to the data file. Then it is read in, maybe something like
1. Jane Doe
2. John Doe
and the program ends.
However, my output seems to add one more blank structure to the end.
1. Jane Doe
2. John Doe
3.
I'd like to know why this is. Keep in mind I'm reading the file until fread returns a 0 to signify it's hit the EOF.
Thanks :)
Change your loop:
while( fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp) )
{
// other stuff
}
Whenever you write file reading code ask yourself this question - "what happens if I read an empty file?"
You have an algorithmic problem in your loop, change it to:
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
while(read != 0)
{
//read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
loop++;
count++;
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
}
There are ways to ged rid of the double fread but first get it working and make sure you understand the flow.
Here:
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
You are not checking whether the read was successful (the return value of fread()).
while( 1==fread(&tempParty[loop],sizeof*tempParty,1,fp) )
{
/* do anything */
}
is the correct way.
use fopen("data","rb")
instead of fopen("data","r") which is equivalent to fopen("data","rt")
You've got the answer to your immediate question but it's worth pointing out that blindly writing and reading whole structures is not a good plan.
Structure layouts can and do change depending on the compiler you use, the version of that compiler and even with the exact compiler flags used. Any change here will break your ability to read files saved with a different version.
If you have ambitions of supporting multiple platforms issues like endianness also come into play.
And then there's what happens if you add elements to your structure in later versions ...
For robustness you need to think about defining your file format independently of your code and having your save and load functions handle serialising and de-serialising to and from this format.

Resources