c find exact word from string starting with " - c

i am doing an exercise in C for my C programming course. I have to read data from a text file into a linked list and look for matches, then print the result out.
Example of the text file:
"Apple/Orange",1
"Banana/Watermelon/Lemon",2
"Watermelon/Strawberry",3
"Orange/Grape/Watermelon",4
"Blueberry", 5
Stored them into my linked list by using fgets(), sscanf() and a void function, therefore the string will be starting with a quotation mark.
The problem is when i tried to use strncmp() to find a word from the string, it didn't work due to the quotation mark.
I did something like:
void findFruits(List *list){
Node *position = list->first;
while(position != NULL){
if(strncmp(position->fruits, "Watermelon", 10)==0){
printf("%s, %d\n", position->fruits, position->number);
}
position = position->next;
}
I literally have no clue for finding an exact word from the string which is beginning with a quotation mark, any help would be appreciated, thanks.
Solved now, thanks to Barmar's idea. It worked perfectly when i tried to use strstr() instead of strncmp().
if(strstr(position->fruits, "Watermelon")){
printf("%s, %d\n", position->fruits, position->number);
}

if you want search a single fruit word, for instance Watermelon in a string Banana/Watermelon/Lemon, you can't compare those two string but you must split your string with this separator / and compare the word between two separator; or you can compare a single character of your fruit with your string.

Related

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

Searching for string that contains escaped characters

I have a binary file that has this particular string in it: ^#^Aname^#Team Fortress 2
This is how I tried to find it using memmem:
char *game = "Team Fortress 2";
sprintf(searchString,"\1\1name\1%s\0",game);
...
if(pos = memmem(buffer,result,searchString,strlen(searchString)))
How do I match the escaped characters ^# and ^A?
It seems to find \1\1name, but not with game in searchString.
Because your string contains nulls it isn't a valid C string and string manipulation functions such as memmem and strlen won't work. You'll have to roll your own version.
The simplest way is to loop through each index of the string, then use a second loop to check it against the string you're searching for. There are fancier and faster methods, but they are more difficult to understand and implement properly if you don't need the extra speed. See Wikipedia for an overview of the subject.
It isn't caret notation?
char *game = "Team Fortress 2";
sprintf(searchString,"%c%cname%c%s\0",(char)0, (char)1, (char)0, game);
...
if(pos = memmem(buffer,result,searchString,strlen(searchString)))

Parsing a line in C

I have a file, in which each line contains several words that are separated by variable amount of whitespace characters (spaces and tabs). For example:
do that param1 param2 param3
do this param1
(The number of words in a line is unknown in advance and is unbounded)
I'm looking for a way to parse such a line in plain C, so that I'll have a pointer to string containing the first word, a pointer to a string containing the second word, and a pointer to a string containing everything else (that is - all of the line, except the first two words). The idea is that the "rest of the line" string will be further parsed by a callback function, determined by the first two words).
Getting the first two words is easy enough (a simple sscanf), but I have no idea how to get the "rest of the line" pointer (As sscanf stops at whitespace, and I don't know the amount of whitespace before the first word, and between the first and the second word).
Any idea will be greatly appreciated.
You can use sscanf for the rest of the line as well. You just use a "scanset" conversion instead of a string conversion:
char word1[256], word2[256], remainder[1024];
sscanf(input_line, "%255s %255s %1023[^\n]", word1, word2, remainder);

in C: reading input string, finding it in char array

writing another program, it reads a txt file, and stores all the letter characters and spaces (as \0) in a char array, and ignores everything else. this part works.
now what i need it to do is read a user inputted string, and search for that string in the array, then print the word every time it appears. im terrible at I/O in C, how do you read a string then find it in a char array?
#include <stdio.h>
...
char str [80];
printf ("Enter your word: ");
scanf ("%s",str);
char* pch=strstr(fileData,str);
while (pch!=NULL)
{
printf ("found at %d\n",pch-fileData+1);
pch=strstr(pch+1,str);
}
read in the user inputted string as a char array as well (cause strings are basically char* anyway in C)
use a string matching algorithm like Boyer-Moore or Knutt-Morris-Pratt (more popularly known as KMP) - google for it if you like for C implementations of these - cause they're neat, tried and tested ways of searching strings for substrings and pattern matches and all.
for each of these indexOf cases, print the position where the word is found maybe? or if you prefer, the number of occurrences.
Generally, the list of C string functions, found here, say, are of the format str* or strn*, depending on requirements.
One for-loop inside another for-loop (called nested loop). Go through all the letters in your array, and for each letter go through all the letters in your input string and find out if that part of the array matches with the input string. If it does, print it.

How to retrieve the telephone number from an AT CMGL response?

I have an application written in C that reads text messages from a modem using AT commands. A typical AT response from the modem looks like this:
+CMGL: 1,"REC READ","+31612123738",,"08/12/22,11:37:52+04"
The code is currently set up to only retrieve the id from this line, which is the first number, and it does so using the following code:
sscanf(line, "+CMGL: %d,", &entry);
Here, "line" is a character array containing a line from the modem, and "entry" is an integer in which the id is stored. I tried extending this code like this:
sscanf(line, "+CMGL: %d,\"%*s\",\"%s\",", &entry, phonenr);
I figured I would use the %*s to scan for the text in the first pair of quotes and skip it, and read the text in the next pair of quotes (the phone number) into the phonenr character array.
This doesn't work (%*s apparently reads "REC" and the next %s doesn't read anything).
An extra challange is that the text isn't restricted to "REC READ", it could in fact be many things, also a text without the space in it.
Sscanf is not very good for parsing, use strchr rather. Without error handling:
#include <stdio.h>
int main(void)
{
const char *CGML_text = "+CMGL: 1,\"REC READ\",\"+31612123738\",,\"08/12/22,11:37:52+04\"";
char *comma, *phone_number_start, *phone_number_end;
comma = strchr(CGML_text, ',');
comma = strchr(comma + 1, ',');
phone_number_start = comma + 2;
phone_number_end = strchr(phone_number_start, '"') - 1;
printf("Phone number is '%.*s'\n", phone_number_end + 1 - phone_number_start, phone_number_start);
return 0;
}
(updated with tested, working code)
The way I solved it now is with the following code:
sscanf(line, "+CMGL: %d,\"%*[^\"]\",\"%[^\"]", &entry, phonenr);
This would first scan for a number (%d), then for an arbitrary string of characters that are not double quotes (and skip them, because of the asterisk), and for the phone number it does the same.
However, I'm not sure yet how robust this is.
You can use strchr() to find the position of '+' in the string, and extract the phone number after it. You may also try to use strtok() to split the string with '"', and analyze the 3rd part.
%s in scanf() reads until whitespace.
You're very close to a solution.
To read this;
+CMGL: 1,"REC READ"
You need;
"+CMGL: %d,"%*s %*s"

Resources