reading a line into three variables - c

I want to read lines from a text file and store the information in three variables. For example, if the line from a file is
A Tale of Two Cities Charles Dickens 1859
I want to store this into two char arrays and one int variable. So, I want to extract the following information from the line. There is no delimiter like comma or hyphen in the line.
title[] = "A Tale of Two Cities"
author[] = "Charles Dickens"
year = 1859
How can this be done in C? Problem is that title could have variable number of words in it. Same for the author. If there was fixed number of words in either of them, then problem is easy. So, what is the desirable solution here ?

The fact that there are two spaces between the title and the author is a delimiter itself. Split on that:
// Find the separation between title and author
char * sep1 = strstr( line, " " );
if (!sep1) fooey();
// Find the separation between the author and the year
char * sep2 = strrchr( sep1+2, ' ' );
if (!sep2) fooey();
// Parse out the data
*sep1 = *sep2 = '\0';
strcpy( title, line );
strcpy( author, sep1+2 );
year = strotol( sep2+1, NULL );

If these files have a predefined file format, your best bet is to find out what that format is; only then will you be able to even begin writing a program that reads the files.
If, on the other hand, these files are something you personally made up, then the format is completely up to you; but whatever format you choose, you have to ensure that each file conforms to it. After you have decided this format, you can begin to design a parser that reads the files.
If you do not know in advance the number of spaces between fields, then you have to use a delimiter, which is a symbol that definitively marks the end of that field. For example:
A Tale of Two Cities Charles Dickens 1859
Could be:
A Tale of Two Cities |Charles Dickens| 1859|
Where the pipe symbol is the delimiter. Then, you can separate each field by looking for the pipe, ignoring leading and trailing spaces afterwards.

Related

C program to display words to end with 'ent' from a txt file

Hello i have being trying to count then display the words that end with 'ent' from a file and tried to do that using the following code but i couldn't even count them.
this is the function i tried to use to count the words it is supposed to read text from a file then count and display to the terminal the words that end with 'ent'.
please help me achieve that if you have an idea how to do it.
void ent(FILE*output){
char s[250];
int ent, i;
output = fopen("output.txt", "r");
while(fgets(s, 250, output)){
if((s[i]=='e') && (s[i+1]=='n' )&& (s[i+2]=='t')){
ent++;
}
}
printf("le nbr de mots avec ent est: %d\n",ent);
fclose(output);
}
You want to use a Regular Expression, or regex for short. The most basic explanation one can give is that it is a form of notation that allows you to match patterns in text. In essence, you can run it against every line in your text file and check how many times a match is found.
The regex you are looking for is ^.*ent$:
^ matches the start of a line.
. matches any character, while adding the Kleene Star * allows any number of characters to be matched.
ent literally matches the characters ent.
$ is the end-of-line symbol.
Depending on the implementation of your programming language (and OS in the case of C), there can be numerous options that can be applied such as "multiline", "global", etc. Standard Linux documentation can be found here.
If you wish to look at an example, you can take a look at this function of mine, in which I use regular expressions to parse IPv4 and IPv6 port numbers.

Separating multiple first and/or last names in C

So I'm working on a small project whereas I want to take mock data and separate them into structs. But I was thinking of the issue of people with multiple first and/or last names.
I want to write first names like you would do (like "Michael") and last names in all capital letters (like "JAMESON").
But what if I'm reading a name like Michael Daniel VAN DOORNE, etc. I don't know how I'd be able to separate "Michael Daniel" as first name, and "VAN DOORNE" as the last name. I tried to separate by stopping at the first capital letter, but I am of course capitalizing the first letter in someone's first names as well.
Example:
I want to read Michael Daniel VAN DOORNE, and separate it into "Michael Daniel" as firstname, and "VAN DOORNE" as the surname.
sscanf(buffer, "%s %s", firstName, lastName);
That wouldnt work naturally. But i am kinda stuck on coming up with a solution for mock names with multiple first and last names.
As you seem to be in total control of the data, I rather recommend a different approach:
A specific separator character in between forename(s) and surname(s). Then you don't rely on case sensitivity any more, especially the single character name issue appearing in another answer isn't an issue any more.
Separator character should be one that won't ever appear in any name, such as a tab (in contrast to space) character, #, '|', ... Even comma or semicolon should be fine, though the period might appear in abbreviated names and thus should not be used.
So knowing if it is part of a first name or last name is a bit of a challenge, but from the sound of it, you are in control of the data, so you can either lowercase the first name and capitalize the last or use some other method.
Breaking up the string, this is relatively easy by using strtok.
Making some assumptions that you are reading names line by line and stuffing them into buffer.
Use strtok to break buffer into "names".
char *token
token = strtok(buffer, " "); //note the second parameter is what you want to parse the array by
while(token != NULL)
{
if(isupper(token[0]))
//store that token into your struct (first or last name) allow for multiple
else
//store into the other
token = strtok(NULL, " "); //keep looping on string for names
}
Assuming last names are always written in upper case, start reading the string from the end and see when you have your last lower case.
int i=strlen(buffer)-1;
while(!islower(buffer[i]) && i>0)
i--;
strncpy(firstName,buffer,i+1);
strcpy(lastName,&buffer[i+2]);
Here's another solution.Read until there are two capitals after each other or a capital and a space. Then use pointer arithmetic to fill first name and lastname.
char name[] = "Michael Daniel VAN DOORNE";
char *p = name;
char firstname[100] = { 0 };
char lastname[100] = { 0 };
while (*p)
{
if (isupper(p[0]) && (isupper(p[1]) || p[1] == ' '))
{
strcpy(lastname, p);
strncpy(firstname, name, p - name - 1);
break;
}
p++;
}
If you're working with ASCII, here is a charset-specific trick that will help you:
#define TWOUPPER(c0, c1) (!((c0) & 32) && !((c1) & 32))
This will work even on single character last names since the null character will fail the 5th bit check, and single character middle names will not be taken as the last name since the following space will not succeed the test.
Works with the following test cases for me by comparing every two characters in the string and stopping on a match:
char test1[100] = "Otto VON BISMARK",
test2[100] = "Johannes Diderik VAN DER WAALS",
test3[100] = "Vincent VAN GOGH",
test4[100] = "Govind A B C D P"; // Only the "P" is counted as the last name here

How can I read in (cin) 2 consecutive words in a line of input, that has more than 2 words?

I need to read in values from the user, such as license plate, name, phone number, and service type.
I already got how to read it in if the user uses the return character after each input, ie:
A36 HTY
John Doe
(263)7742336
Bronze
But how can I read these values into my array if they're all on one line? I can read in word by word, but I need to be able to read in both halves of the license plate, and both the first and last name into one spot in the array.
I'd appreciate any help, thanks!
read the entire line and then use your software's programming to check whether there is any white space(s) in between the non-white spaces, and if there is, break the read string at the white space(s) into two different strings.
You can use isspace.
Use this link for assistance:
https://www.geeksforgeeks.org/isspace-in-c-and-its-application-to-count-whitespace-characters/
In this example, they use isspace for counting the number of whitespaces in a string. You can change the code to save each word in different string. Since I didn't write cpp for quite time now, I don't want to give you example that might be incorrect.
// input sentence
char buf[50] = "Geeks for Geeks";
ch = buf[0];
// counting spaces
while (ch != '\0') {
ch = buf[i];
if (isspace(ch))
count++;
i++;
}
// returning number of spaces
return (count);

read from text file and put into struct

i have assembler file actually text file like that
1 # Test case 1 for assembler
2
3 .text
4 test1: lwa $1,val1
5 prh $1
6 val12: lwa $2,val2
7 prh $2
..................
i am reading each line with fgets and keeping in char buffer which name is "linebuffer"
and im reading linebuffer with sscanf.
while((fgets(linebuffer,sizeof(linebuffer),ifp)!=NULL)
{
sscanf(linebuffer,"%s%s%s%s",line[i].label,line[i].opcode,line[i].operands,line[i].comment);
......
}
and i want keep them into struct,
struct instrucion{
char lable[8];
char opcode[4];
char opearand[15];
char comment[100];
}line[65536];
problem is some columns doesnt have anything just space and sscanf skipping spaces and reading very next string and keeping in first column. sorry i could not understand exactly but i hope somebody is understand.
for example i want like that for 3rd line;
line[2].label=NULL
line[2].opcode=".text"
line[2].opernds=NULL
line[2].comment=NULL
for 4th line;
line[3].label="test1:"
line[3].opcode="lwa"
line[3].operands="$1,val1"
line[3].comment=NULL
problem is starting with 5th line its has to be like that
line[4].label=NULL
line[4].opcode="prh"
line[4].operands="$1"
line[4].comment=NULL
buts when i run code im getting this result;
line[4].label="prh"
line[4].opcode="$1"
line[4].opernds=NULL
line[4].comment=NULL
how can i deliminate this linebuffer correctly?
OK, so your first problem is that fgets() does not read one line - It reads up to sizeof(linebuffer) number of bytes, you can see it's man page here:
http://linux.die.net/man/3/gets
Second, say that you do have only one line in the string "linebuffer", what you would like to do is use sscanf return value to determine which tokens appear in the line (scanf functions family return the number of parameters that were read from the stream).
Third, pay attention to the fact the scanf considers only spaces and newlines as tokens separators, so it will not separate the string "$1,val1" to the two sub-strings - you will need to do it manually.
And finally, there's a string-parsing function that can maybe make you life easier- strtok_r. You can see it's man page here:
http://linux.die.net/man/3/strtok_r
Amnon.

How to parse this input in C

Right now i am doing an assignment but find it very hard to parse the user input in C. Here is kind of input user will input.
INSERT Alice, 25 Norway Drive, Fitzerald, GA, 40204, 6000.60
Here INSERT is the command (to enter in link list)
Alice is a name
25 Norway Drive is an address
Fitzerald is a city
GA is a state
40204 is a zip code
6000.60 is a balance
How can I use scanf or any other method in C to properly take this as input? The biggest problem in front of me is how to ignore these "," and store these values in separate variables of appropriate data types.
Thanks everyone, i have solve the issue and here is the solution:
pch = strtok(NULL, ","); pch =
substr(pch, 2, strlen(pch)); //substr is my custom funcition and i believe you can tell by its name what it is doing.
strcpy(customer->streetAddress, pch);
Fast easy method:
Use fgets() to get the string from the user;
and strtok() to tokenize it.
Edit
After reading your comment:
Use strtok() with only the comma, and then remove trailing and leading spaces from the result.
Edit2
After a test run, I noticed you will get "INSERT Alice" as the first token. So, after all tokens have been extracted, run strtok() again, this time with a space, on the first token extracted. Or, find the space and somehow identify the command and the name from there.
If your input data format is fixed you can use something quick and dirty using [s]scanf().
With input of:
INSERT Alice, 25 Norway Drive, Fitzerald, GA, 40204, 6000.60
You might try, if reading from stdin:
char name[80], addr[80], city[80], state[80];
int zip;
double amt;
int res = scanf("INSERT %[^,], %[^,], %[^,], %[^,], %d, %f\n",
&name, &addr, &city, &state, &zip, &amt);
Should return the number of items matched (i.e. 6).
scanf() may be a bit tricky in this situation, assuming that different commands with different parameters can be used. I would probably use fgets() to read in the string first, followed by the use of strtok() to read the first token (the command). At that point you can either continue to use strtok() with "," as the delimiter to read the rest of the tokens in the string, or you could use a sscanf() on the rest of the string (now that you know the format that the rest of the input will be in). sscanf() is still going to be a pain due to the fact that it appears that an unspecified number of spaces would be allowed in the address and possibly town fields.

Resources