Splitting string using delimiter in c [closed] - c

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
My input string is 1,2,3:4,5,6:7,5,8
First I need to split 1, 2, 3 set wit : delimiter. Then again I need to split 1 2 3 with , delimiter. So I need to do outer split and inner split till the end of input string.. Please explain me with some example

As coderredoc says, strtok is the function you need.
#include <string.h>
char *strtok(char *str, const char *delim);
But strtok have some
quirks you have to remember:
Only in the first call you have to pass the source (str), subsequent
calls of strtok must be passed with NULL
Strtok modifies the source. Do not use unmodifiable strings or string
literal ("this is a string literal")
Because of the previous point, you should always do a copy of the source.
Simple example
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
const char *text = "Hello:World:!";
char *tmp = strdup(text);
if(tmp == NULL)
return 1; // no more memory
char *token = strtok(tmp, ":");
if(token == NULL)
{
free(tmp);
printf("No tokens\n");
return 1;
}
printf("Token: '%s'\n", token);
while(token = strtok(NULL, ":"))
printf("Token: '%s'\n", token);
free(tmp);
return 0;
}
Expected output
Token: 'Hello'
Token: 'World'
Token: '!'
Update
If you need to nest strtok, you should use strtok_r as mentioned before.
Here is an update of my example above. If I'm not mistaken, input will have
the same format as yours (more or less, mine has different set sizes, but same principle)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
const char *input ="v1,v2,v3,v4,v5:w1,w2,w3,w4,w5:x1,x2,x3,x4:y1,y2,y3,y4,y5,y6";
char *input_copy = strdup(input);
char *set_track, *elem_track; // keep track for strtok_r
char *set, *value;
char *_input = input_copy;
int setnum = 0;
while(set = strtok_r(_input, ":", &set_track))
{
_input = NULL; // for subsequent calls of strtok_r
printf("Set %d contains: ", ++setnum);
// in this case I don't care about strtok messing with the input
char *_set_input = set; // same trick as above
while(value = strtok_r(_set_input, ",", &elem_track))
{
_set_input = NULL; // for subsequent calls of strtok_r
printf("%s, ", value);
}
puts("");
}
free(input_copy);
return 0;
}
Expected output
Set 1 contains: v1, v2, v3, v4, v5,
Set 2 contains: w1, w2, w3, w4, w5,
Set 3 contains: x1, x2, x3, x4,
Set 4 contains: y1, y2, y3, y4, y5, y6,

Related

How to extract contents between a specific character in a c string?

Say I have char ch[] = "/user/dir1/file.txt";
I want to use a loop such that:
1st iteration:
prints: "user"
2nd iteration:
prints: "dir1"
3rd iteration:
prints: "file1.txt"
reach the end of string. Exists the loop
You have to use strtok or its threadsafe version if you are developing a multithreaded program:
#include<stdio.h>
#include <string.h>
int main() {
char ch[] = "/user/dir1/file.txt";
// Extract the first token
char * token = strtok(ch, "/");
// loop through the string to extract all other tokens
while( token != NULL ) {
printf( "%s\n", token ); //printing each token
token = strtok(NULL, " ");
}
return 0;
}
A "simple", portable, thread-safe solution that does not modify the string, as the approach using strtok() does. So the approach below can be applied to literals as well!
#include <stdio.h>
#include <string.h>
int main(void)
{
const char * s = "/user/dir1/file.txt";
for (const char * ps = s, *pe;
pe = strchr(ps, '/'), ps != pe ?printf("%.*s\n", (int) (pe - ps), ps) :0, pe;
ps = pe + 1);
}
The only limitation this code is facing, is that the tokens within the string to be parsed may not be longer then INT_MAX characters.

Using strtok to store a simple equation into an array and then perform the operation?

I am trying to use strtok to break a simple equation like 5 + 4 down and store each part into an array, and once I have done this, perform the operation indicated.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
//#include "stdafx.h"
int main() {
char uin[10], op[10], error = 'e';
char *token;
const char s[2] = " ";
double num1, num2, fNum1, res;
int i = 0;
int x, y, z, a, b, c, op1;
printf("Welcome to the calculator, please enter an equation\n");
while (error == 'e') { // & assigns address and * gives access to what it points to
a = &uin[0];
b = &uin[2];
c = &uin[4];
gets(uin);
rewind(stdin);
printf("Is this what you entered? %s\n", uin);
token = strtok(uin, s);
//x = &token;
//printf("The element in the array currently assigned to token is: %s\n", token);
while (token != NULL) {
if (isdigit(token[0])) {
num1 = atof(token);
printf("token is now: %1.2f\n", num1);
} else
strcpy(op, token);
token = strtok(NULL, s);
if (isdigit(token[0])) {
num1 = atof(token);
} else
strcpy(op, token);
//token = strtok(NULL, s);
//y = &token;
//printf("The element in the array currently assigned to token is: %s\n", token);
}
//token = strtok(NULL, s);
//y = &token;
//printf("The element in the array currently assigned to token is: %s\n", token);
//token = strtok(NULL, s);
//z = &token;
//printf("The element in the array currently assigned to token is: %s\n", token);
}
system("pause");
}
I am really having a hard time with this. I think that I am using strtok correctly to take the first part of the gets(uin) and storing it, but I don't understand how to take the middle part (+ - * or /) and store it.
strtok is not the proper tool for your purpose. strtok modifies the string, overwriting the separator. It would only work for expressions where all tokens are separated by spaces, an unnecessary and counterintuitive constraint. For a more effective approach, either use a pointer and explicit tests for each character or use non intrusive parsing helpers such as strspn(), strcspn() and strtold().
Furthermore, you should not use gets(), this function is obsolete and was removed from the latest version of the C Standard. It cannot be used safely: any sufficiently large input will corrupt your program and have undefined behavior. Use fgets() instead to read a full line into a sufficiently large array: 10 bytes is definitely too small. rewind() is also unnecessary.

Extract sub string from a string based on a condition [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I have an input string in the format: name1#float1 name2#float2 ... nameN#floatN. It's always delimited by '#' and ' '.
Example:
ash#19.96 ram#12.3 driver#10.2
It should display the name of the person having the smallest values.
How can it be solved?
Output:
driver
You can combone the strtok and sscanf functions to solve your problem.
For first, you have to tokenize your string using ' ' (white-space) as delimiter, then extract the number from each token to find the token with smallest number. Every time you find a token with smaller number than the current, extract the name from that token and store the new possibly smallest number. Here is an example:
#include <string.h>
#include <stdio.h>
#include <float.h>
int main() {
char str[] = "ash#19.96 ram#12.3 driver#10.2";
char result[256] = { 0 };
char *token, *sep_ptr;
float value, min = FLT_MAX; /* set 'min' to the maximum of float */
/* tokenize 'str' and walk through the tokens */
for(token = strtok(str, " "); token != NULL; token = strtok(NULL, " ")) {
value = FLT_MAX;
/* process the current token if it contains a '#' character */
if(sep_ptr = strchr(token, '#')) {
sscanf(sep_ptr, "#%f", &value); /* extract value */
/* check if the new number is smaller than current 'min' */
if(value < min) {
strcpy(result, (*sep_ptr = '\0', token)); /* extract name */
min = value;
}
}
}
puts(result);
return 0;
}
The (*sep_ptr = '\0', token) part of the code above simply replaces the '#' character to null character before performing the copy from token to result. (The mentioned expression uses the comma operator.)
The following code implements a getSubstrSmallestNumber() function which uses the strtok() function which changes the input buffer. If you don't want that you can first copy the string. The good point about changing the input buffer is that no memory allocation is needed for the found sub string. The strtok() writes a null terminator '\0' where the specified delimiter is found if it's called.
The getSubstrSmallestNumber() function can called with specific delimiters, here '#' and ' '. Each number will be converted to double with strtod() and checked if it smaller than before. If it's smaller the corresponding token will be saved. After the while loop finished (if strtok() found no more tokens) the saved token (smallest double) will be returned.
Note that the code does no error checking this should be considered to be implemented as well.
Full code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <float.h>
char* getSubstrSmallestNumber(char* input, char* numberDelimiter, char* strDelimiter)
{
char* tokenStr;
double minNumber = DBL_MAX;
char* minToken = NULL;
for (tokenStr = strtok(input, numberDelimiter);
tokenStr != NULL;
tokenStr = strtok(NULL, numberDelimiter))
{
char* numberStr = strtok(NULL, strDelimiter);
double number = strtod(numberStr, NULL);
if (number < minNumber)
{
minNumber = number;
minToken = tokenStr;
}
}
return minToken;
}
int main()
{
char input[] = "ash#19.96 ram#12.3 driver#10.2";
printf("<%s>\n", getSubstrSmallestNumber(input, "#", " "));
return 0;
}
Output:
<driver>
I put '<' and '>' around the string in the printf() call to show that the returned string by getSubstrSmallestNumber() is really just driver and nothing more like a space for example.
You can use strrok available in C string library and for parsing float you can use atof function but the atof function seems to be unreliable in some cases, though. In that case you can write your own implementation according to your needs.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <float.h>
#define SIZE 1000
int main() {
char input[SIZE], smallest[SIZE], name[SIZE];
const char s[2] = "#";
char *token;
float val = FLT_MAX;
while(scanf("%s", input) != EOF) {
token = strtok(input, s);
strcpy(name, token);
token = strtok(NULL, s);
float curVal = atof(token);
if(curVal < val) {
val = curVal;
strcpy(smallest, name);
}
}
printf("Smallest value : %s\n", smallest);
return 0;
}
When i tested it seemed to show correct output:
~/Documents/src : $ ./a.out
ram#12.3
driver#10.2
ash#19.96
Smallest value : driver
Hope that helps!

Changing word "welcome" to uppercase from the input string [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I want to convert the case of word "welcome" from the given string.
All occurrences should have been changed.
What I have tried is below code,
#include "stdio.h"
#include <string.h>
#include "ctype.h"
int main(int argc, char const *argv[]) {
printf("Enter the sentence you need to display via app:\n");
char sentence[100];
char word[10] = {"welcome"};
scanf("%[^\n]s", sentence);
getchar();
char * pch;
pch = strtok (sentence," ,.-");
while (pch != NULL)
{
if (strcmp(pch,word) == 0) {
while(*pch != '\0'){
*pch = toupper(*pch);
}
}
printf("%s\n", pch);
pch = strtok (NULL," ,.-");
}
printf("%s\n", sentence);
return 0;
}
/*
Output:
Enter the sentence you need to display via app:
welcome here welcome there
*/
The program takes forever and doesn't work as expected.
Thanks in advance.
There are many issues in your program:
The syntax for standard include files in #include <stdio.h>, using < and > instead of ".
You should define word as a pointer: const char *word = "welcome"; or an array without a length to let the compiler compute it for you: char word[] = "welcome";.
The syntax for scanf character ranges is %[^\n], without a trailing s. You should specify the limit as %99[^\n].
scanf() will fail if you enter an empty line. You should test the return value to avoid undefined behavior upon failure to read.
It would be safer to use fgets() to read a line of input.
You do not increment pch in the loop, hence the infinite loop taking for ever to execute.
toupper must not be passed a naked char, you must convert the char to unsigned char to avoid potential negative values that produce undefined behavior.
strtok has modified the sentence, you printing it will only print the first word (along with any preceding separators).
Here is a corrected version:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[]) {
char sentence[100];
char word[] = "welcome";
printf("Enter the sentence you need to display via app:\n");
if (fgets(sentence, sizeof sentence, stdin)) {
char *pch = strtok(sentence, " ,.-");
while (pch != NULL) {
if (strcmp(pch, word) == 0) {
char *p;
for (p = pch; *p != '\0'; p++) {
*p = toupper((unsigned char)*p);
}
}
printf("%s ", pch);
pch = strtok(NULL," ,.-");
}
printf("\n");
}
return 0;
}
In your while loop, you are missing to increase pointer for your string. In the example below, I'm using temporary variable here for updating entire string. ptr variable can then later be used for printing purpose.
if (strcmp(pch,word) == 0) {
char *tmp = pch;
while (*tmp != '\0'){
*tmp= toupper(*tmp);
tmp++; //Increase pointer
}
}

Put each word of a string into array in C [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm trying to split up a string (typed in by the user at run time) into words (separated by spaces), and put each word into a different slot into an array. So, for example, if I took the string "hello world", array[0] would contain "hello" and array[1] would contain "world". And the last slot (in this case array[2]) would contain NULL. Here's what I have so far, which doesn't seem to be working properly. Any help would be appreciated. (By the way, this is part of a program which will call execvp(argv[0],argv); )
char input[100];
char* argv[20];
char* token;
scanf("%s", input);
//get the first token
token = strtok(input, " ");
int i=0;
//walk through other tokens
while( token != NULL ) {
argv[i] = token;
i++;
token = strtok(NULL, " ");
}
argv[i] = NULL; //argv ends with NULL
You need to allocate memory for each argv[i] and copy the current token to argv[i]:
token = strtok(input, " ");
int i=0;
//walk through other tokens
while( token != NULL ) {
argv[i] = malloc(strlen(token) + 1);
strncpy(argv[i], token, strlen(token));
//argv[i] = token;
i++;
token = strtok(NULL, " ");
}
argv[i] = NULL; //argv ends with NULL
I have created an example of what I think you want. I have used one malloc(3) for the whole
line of strings and another for the array of pointers you will get from the function.
Also, the second parameter of strtok(3) is passed to give more flexibility (the shell normally uses the contents of IFS environment variable to separate arguments so you can use the same algorithm as the shell does) I think you should use " \n\t" at least. It has a main() test function, so it's complete for your purpose.
#include <assert.h> /* man assert(3) */
#include <stdlib.h> /* malloc lives here */
#include <string.h> /* strtok, strdup lives here */
#include <stdio.h> /* printf lives here */
char **split(const char *str, const char *delim)
{
char *aux;
char *p;
char **res;
char *argv[200]; /* place for 200 words. */
int n = 0, i;
assert(aux = strdup(str));
for (p = strtok(aux, delim); p; p = strtok(NULL, delim))
argv[n++] = p;
argv[n++] = NULL;
/* i'll put de strdup()ed string one place past the NULL,
* so you can free(3), once finished */
argv[n++] = aux;
/* now, we need to copy the array, so we can use it outside
* this function. */
assert(res = calloc(n, sizeof (char *)));
for (i = 0; i < n; i++)
res[i] = argv[i];
return res;
} /* split */
int main()
{
char **argv =
split("Put each word of a string into array in C", " ");
int i;
for (i = 0; argv[i]; i++)
printf("[%s]", argv[i]);
puts(""); /* to end with a newline */
free(argv[i+1]);
free(argv);
} /* main */
The sample code just outputs:
$ pru
[Put][each][word][of][a][string][into][array][in][C]
I think I just figured out my problem: I need to use gets() instead of scanf(), because scanf() only gets the first word, up until a space, while I want to be able to get a string containing multiple words separated by spaces.

Resources