#include <stdio.h>
#include <stdlib.h>
int main(void) {
char command[256];
char *token;
const char s[2] = " ";
fprintf(stdout, "$ Please enter a command \n");
fflush( stdout );
fgets ( command, 256, stdin );
token = strtok(command, s);
if (strcmp(token, "loaddungeon") == 0){
fprintf(stdout, "$ loaded successfully \n");
fflush( stdout );
}
}
I am trying to use strtok to get the second string of the input. For instance, if the input is "loaddungeon dfile.txt", what I want to get is the "dfile.txt". My function is able to get the string "loaddungeon". But I have no idea how to get the second string "dfile.txt". Can anyone tell me how to do it?
(Consider the input is always "loaddungeon dfile.txt".)
To read the second string, you need to pass NULL to strtok(). Keep in mind that fgets() retains the newline character from the input line, so you should change your delimiter definition from char s[2] = " "; to char s[] = " \r\n";, or char s* = " \r\n". This way the second token will not include any newline characters. Also note that strtok() returns a NULL pointer if no token is found, so the below code tests for this before printing the read tokens.
But, since you say that there are only two strings, I would consider just using sscanf() for this. Using the %s conversion specifier, sscanf() will read characters into a string until a whitespace character is encountered, but will not include this whitespace character in the string. When you use the %s specifier in a scanf() type function, you should specify a maximum field width to avoid buffer overflow. This maximum width should be one less than the size of the buffer to leave room for the '\0' string terminator, 255 in this case. The sscanf() function returns the number of successful assignments made, which should be 2 in this case. The sscanf() approach shown below (commented out) checks this return value before printing the strings.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_MAX 256
int main(void) {
char command[BUFFER_MAX];
char *token1 = NULL;
char *token2 = NULL;
const char *s = " \r\n";
fprintf(stdout, "$ Please enter a command \n");
fflush( stdout );
fgets ( command, BUFFER_MAX, stdin );
token1 = strtok(command, s);
token2 = strtok(NULL, s);
if (token1 && token2 && strcmp(token1, "loaddungeon") == 0) {
fprintf(stdout, "$ loaded successfully: %s\n", token2);
fflush( stdout );
}
/* or instead do this */
/*
char word1[BUFFER_MAX], word2[BUFFER_MAX];
if (sscanf(command, "%255s %255s", word1, word2) == 2) {
if (strcmp(word1, "loaddungeon") == 0){
fprintf(stdout, "$ loaded successfully: %s\n", word2);
fflush( stdout );
}
}
*/
return 0;
}
Every call to strtok will return a pointer to the last token found in the given string (or null if there is none left). To retrieve the second token with space as a delimiter, you need to call strtok for the second time.
int main()
{
char command[256];
char *token1 = NULL;
char *token2 = NULL;
const char s[2] = " ";
fprintf(stdout, "$ Please enter a command \n");
fflush(stdout);
fgets(command, 256, stdin);
token1 = strtok(command, s); // now points to first word
if (NULL != token1) {
token2 = strtok(NULL, s); // now points to second word
}
if (NULL != token2) {
if (strcmp(token2, "loaddungeon") == 0){
fprintf(stdout, "$ loaded successfully \n");
fflush(stdout);
}
}
}
Related
I'm having some trouble when parsing a text file. Each line of the text has a name followed after three float values. All of them are separated by a blankspace. What I want is to store the name in a string and the numbers in an array. I know I have to read each line using fgets and then strtok but the thing is I don't understand how strtok works. Do I have to call strtok four times? How do I assign each "piece" to my variables ?
Thank you for your time!
The strtok will search for the given tokens in a string. You must call it until the it returns NULL.
char *strtok(char *str, const char *delim)
The first call is done passing the string (char*) as the argument str and the remaining times are done passing NULL, as this will define that it should keep looking for the next token from that point onwards.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char line[] = "name 1.45 2.55 3.65";
char* name;
double values[3] = { 0 };
char* ptr = NULL;
int i = 0;
ptr = strtok(line, " "); // Search for the first whitespace
if (ptr != NULL) // Whitespace found
{
/* 'line' is now a string with all the text until the whitespace,
with terminating null character */
name = calloc(1, strlen(line));
strcpy(name, line);
while ((i < 3) && (ptr != NULL))
{
ptr = strtok(NULL, " "); // Call 'strtok' with NULL to continue until the next whitespace
if (ptr != NULL) // Whitespace found
{
/* 'ptr' has now the text from the previous token to the found whitespace,
with terminating null character */
values[i] = atof(ptr); // Convert to double
}
i++;
}
}
printf("%s %lf %lf %lf\n", name, values[0], values[1], values[2]);
}
I'm making a client-server program using sockets, and I need to client to be able to send a message to the server as a command, for example 'user 3' which connects the user to user 3.
So far everything is working but I don't know how to separate the string into its useful parts. I need to first check the command which is 'user' and then check the second word which in this case is '3'.
So far I have only managed to split it using the '\0' delimiter which isn't proving to be all that useful, it only allows me to check is the user has said 'user' or '3'.
char receive[1024];
int read = recv(client_socket, &receive, 1024, 0);
receive[read] = '\0';
if (strcmp(receive, "user") == 0) {
printf("User has requested chat with....");
}
For your use case you should be using
char *strstr(const char *haystack, const char *needle);
it finds the substring in the provided string.
For example:
char receive[1024];
int read = recv(client_socket, &receive, 1024, 0);
receive[read] = '\0';
if (strstr(receive, "user")) {
printf("User has requested chat with....");
}
The strtok() function is what exactly you need. It separates the string with the given delimiters, here it is whitespace.
char receive[1024];
int read = recv(client_socket, &receive, 1024, 0);
receive[read] = '\0';
char *token = strtok(receive, " "); // get the first part
while (token != NULL) { // while there still have unprocessed parts
// handle the commands, values, whatever you want
if (strcmp(receive, "user") == 0) {
printf("User has requested chat with....");
}
token = strtok(NULL, " "); // get the next part
}
Use strtok function which two parameters one the string and one the delimiter.
#include <stdio.h>
#include <string.h>
int main ()
{
char strtest[] ="- This, a string for testing.";
char * pchs;
printf ("Splitting string \"%s\" in token:\n",str);
pch = strtok (strtest," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
I am working on creating a simple version of Minix. I am using fgets() to grab user input. I am then using strtok() to split the string up with the delimiter " ". The problem is when I call strtok(NULL, " "), my token stored appends a space to the last char. So if I pass "minimount imagefile.img", my program will grab minimount and store it in variable cmd, then it will grab "imagefile.img " and place it in variable flag. Notice the space at the end of the flag variable is added after the token method.
Is there a way for me to grab just the string without a space at the end after token is called. Or is there a way to manipulate the string to remove the appended space?
printf("Minix: ");
fgets(cmd, BUFFLIM, stdin);
//parses string using delimiter " "
char *token = strtok(cmd, " ");
//assigns flag to what is after delimiter
char *f = strtok(NULL, " ");
//printf("cmd:%s\nf:%s\n", cmd, f);
printf("cmd:%s\nf:%s", cmd, f);
Output:
cmd:"minimount"
f:"imagefile.img "
The standard function fgets can append the new line character '\n' to the entered string provided that there is enough space in the corresponding character array.
So use
char *f = strtok(NULL, " \n");
instead of
char *f = strtok(NULL, " ");
From the C Standard (7.21.7.2 The fgets function)
2 The fgets function reads at most one less than the number of
characters specified by n from the stream pointed to by stream into
the array pointed to by s. No additional characters are read after a
new-line character (which is retained) or after end-of-file. A null
character is written immediately after the last character read into
the array.
Another approach is initially to remove the character from the entered string as for example
#include <string.h>
#include <stdio.h>
//...
fgets(cmd, BUFFLIM, stdin);
cmd[ strcspn( cmd, "\n" ) ] = '\0';
As for your code snippet then it seems you have the following result as it is shown in the demonstrative program.
#include <stdio.h>
#include <string.h>
int main(void)
{
char s[100];
fgets( s, sizeof( s ), stdin );
char *cmd = strtok( s, " " );
char *f = strtok( NULL, " " );
printf( "cmd:\"%s\"\nf:\"%s\"", cmd, f );
return 0;
}
The program output is
cmd:"minimount"
f:"imagefile.img
"
I have a struct named excuses that has chars, I need to store at least 20 excuses. Then, I need to divide each word of each excuse in an array.
¿How i can do that?
#define excuseLength 256
typedef struct{
char sentence[excuseLength];
}excuse;
excuse listExcuses[20];
for (int listExcuses_i = 0; listExcuses_i < 20; listExcuses_i++)
{
char *input;
scanf("%s", input);
strcpy(listExcuses[listExcuses_i].sentence, input);
char* token = strtok(input, " ");
while(token != NULL){
printf("token: %s\n", token);
token = strtok(NULL, " ");
}
}
Here are some things you can add to your solution:
Check fgets() for return value, as it returns NULL on error.
If you decide to still use scanf(), make sure to use scanf("%255s", input) instead for char input[256]. Using the format specifier %255s instead of the simpe %s checks for excessive input. Overall, it just better to read input using fgets().
Remove '\n' character appended by fgets(). This is also good for checking that you don't enter more characters than the limit of 256 in input, and that your sentences don't have a trailing newline after each of them. If you don't remove this newline, then your strtok() delimiter would have to be " \n" instead.
#define constants in your code, and use const char* for string literals, such as the delimiter for strtok().
You can also add some code to check for empty inputs from fgets(). You could simply use a separate counter, and only increment this counter for valid strings found.
It's also strange to have struct with one member, usually structs contain more than one member. You could simply bypass using a struct and use a 2D char array declared as char listexcuses[NUMEXCUSES][EXCUSELENGTH]. This array can hold up to 20 strings, each of which has a maximum length of 256.
Here is some modified code of your approach:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define EXCUSELENGTH 256
#define NUMEXCUSES 20
typedef struct {
char sentence[EXCUSELENGTH];
} excuse;
int main(void) {
excuse listexcuses[NUMEXCUSES];
char input[EXCUSELENGTH] = {'\0'};
char *word = NULL;
const char *delim = " ";
size_t slen, count = 0;
for (size_t i = 0; i < NUMEXCUSES; i++) {
printf("\nEnter excuse number %zu:\n", count+1);
if (fgets(input, EXCUSELENGTH, stdin) == NULL) {
fprintf(stderr, "Error from fgets(), cannot read line\n");
exit(EXIT_FAILURE);
}
slen = strlen(input);
if (slen > 0 && input[slen-1] == '\n') {
input[slen-1] = '\0';
} else {
fprintf(stderr, "Too many characters entered in excuse %zu\n", count+1);
exit(EXIT_FAILURE);
}
if (*input) {
strcpy(listexcuses[count].sentence, input);
count++;
printf("\nTokens found:\n");
word = strtok(input, delim);
while (word != NULL) {
printf("%s\n", word);
word = strtok(NULL, delim);
}
}
}
return 0;
}
As you need to eventually store these tokens somewhere, you will need another form of storing this data. Since you don't know how many tokens you can get, or how long each token is, you may need to use something like char **tokens. This is not an array, but it is a pointer to a pointer. Using this would allow any number of words and any lengths of each word to be stored. You will need dynamic memory allocation for this. The answer in this post will help.
I changed the scanf for fgets and initialize the char input[256] and with that now it works!
#define excuseLength 256
#define numberExcuses 20
typedef struct{
char sentence[excuseLength];
}excuse;
excuse listExcuses[20];
for (int listExcuses_i = 0; listExcuses_i < numberExcuses; listExcuses_i++)
{
char input[256];
scanf("%s", input);
fgets(input, 256, stdin);
strcpy(listExcuses[listExcuses_i].sentence, input);
char* token = strtok(input, " ");
while(token != NULL){
printf("token: %s\n", token);
token = strtok(NULL, " ");
}
}
I'm trying to scan a line that contains multiple words in C. Is there a way to scan it word by word and store each word as a different variable?
For example, I have the following types of lines:
A is the 1 letter;
B is the 2 letter;
C is the 3 letter;
If I'm parsing through the first line: "A is the 1 letter" and I have the following code, what do I put in each case so I can get the individual tokens and store them as variables. To clarify, by the end of this code, I want "is," "the," "1," "letter" in different variables.
I have the following code:
while (feof(theFile) != 1) {
string = "A is the 1 letter"
first_word = sscanf(string);
switch(first_word):
case "A":
what to put here?
case "B":
what to put here?
...
You shouldn't use feof() like that. You should use fgets() or equivalent. You probably need to use the little-known (but present in standard C89) conversion specifier %n.
#include <stdio.h>
int main(void)
{
char buffer[1024];
while (fgets(buffer, sizeof(buffer), stdin) != 0)
{
char *str = buffer;
char word[256];
int posn;
while (sscanf(str, "%255s%n", word, &posn) == 1)
{
printf("Word: <<%s>>\n", word);
str += posn;
}
}
return(0);
}
This reads a line, then uses sscanf() iteratively to fetch words from the line. The %n format specifier doesn't count towards the successful conversions, hence the comparison with 1. Note the use of %255s to prevent overflows in word. Note too that sscanf() could write a null after the 255 count specified in the conversion specification, hence the difference of one between the declaration of char word[256]; and the conversion specifier %255s.
Clearly, it is up to you to decide what to do with each word as it is extracted; the code here simply prints it.
One advantage of this technique over any solution based on strtok() is that sscanf() does not modify the input string so if you need to report an error, you have the original input line to use in the error report.
After editing the question, it seems that the punctuation like semi-colon is not wanted in a word; the code above would include punctuation as part of the word. In that case, you have to think a bit harder about what to do. The starting point might well be using and alphanumeric scan-set as the conversion specification in place of %255s:
"%255[a-zA-Z_0-9]%n"
You probably then have to look at what's in the character at the start of the next component and skip it if it is not alphanumeric:
if (!isalnum((unsigned char)*str))
{
if (sscanf(str, "%*[^a-zA-Z_0-9]%n", &posn) == 0)
str += posn;
}
Leading to:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char buffer[1024];
while (fgets(buffer, sizeof(buffer), stdin) != 0)
{
char *str = buffer;
char word[256];
int posn;
while (sscanf(str, "%255[a-zA-Z_0-9]%n", word, &posn) == 1)
{
printf("Word: <<%s>>\n", word);
str += posn;
if (!isalnum((unsigned char)*str))
{
if (sscanf(str, "%*[^a-zA-Z_0-9]%n", &posn) == 0)
str += posn;
}
}
}
return(0);
}
You'll need to consider the I18N and L10N aspects of the alphanumeric ranges chosen; what's available may depend on your implementation (POSIX doesn't specify support in scanf() scan-sets for the notations such as [[:alnum:]], unfortunately).
You can use strtok() to tokenize or split strings. Please refer the following link for an example: http://www.cplusplus.com/reference/cstring/strtok/
You can take array of character pointers and assign tokens to them.
Example:
char *tokens[100];
int i = 0;
char *token = strtok(string, " ");
while (token != NULL) {
tokens[i] = token;
token = strtok(NULL, " ");
i++;
}
printf("Total Tokens: %d", i);
Note the %s specifier strips whitespace. So you can write:
std::string s = "A is the 1 letter";
typedef char Word[128];
Word words[6];
int wordsRead = sscanf(s.c_str(), "%128s%128s%128s%128s%128s%128s", words[0], words[1], words[2], words[3], words[4], words[5] );
std::cout << wordsRead << " words read" << std::endl;
for(int i = 0;
i != wordsRead;
++i)
std::cout << "'" << words[i] << "'" << std::endl;
Note how this approach (unlike strtok), effectively requires an assumption about the maximim number of words to read, as well as their lengths.
I would recommend using strtok().
Here is the example from http://www.cplusplus.com/reference/cstring/strtok/
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
Output will be:
Splitting string "- This, a sample string." into tokens:
This
a
sample
string