Spilting strings in C with mulitple delimiters [duplicate] - arrays

This question already has answers here:
split char string with multi-character delimiter in C
(5 answers)
Closed 1 year ago.
so i need to split the string given with:
const char *inputs[] = {"111adbhsd111gfhds","goal!","zhd!111oosd","111let111"};
to ouput:
char *outputs[]={"adbhsd","gfhds","goal!","zhd!","oosd","let"}
where the delimiter is : "111" .
I tried with strtok , but as the delimiter is of mulitple character , it did't work!
any idea, how it might give the output, will help!
what i have did till now:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
size_t split(
char **outputs, // outputs
const char *separator, // the delimiter
const char **inputs,
size_t num_inputs // no. of input strings, given in input array
){
size_t num_outputs = 0;
int l= 0;
for(size_t i = 0; i < num_inputs ; i++){
if(strstr(*(inputs+i), separator) != NULL){ // to check, if the string of the given input array has the delimiter
char* pos = strstr( *(inputs+i), separator);
//having problem in this part
}
else
{
strcpy( outputs[l] , *(inputs+i));;
l++;
num_outputs++;
}
}
return num_outputs;
}
int main(){
const char *inputs[] = {
"111abdhsd111gfhds",
"goal!",
"zhd!111oosd",
"111let111"
};
char *outputs[] ={malloc(1000),malloc(1000),malloc(1000),malloc(1000),malloc(1000),malloc(1000)};
split(outputs, "111", inputs, 4);
for(int i =0; i < 6; i++)
{
printf("The output[%d] is : %s" ,i, outputs[i]);
free(outputs[i]);
}
return 0;
}

NOTE: The following answer refers to revision 2 of the question, which is before OP added code to the question which already uses the function strstr.
If the string is delimited by a substring instead of a single character, you can use the function strstr to find the delimiter substrings:
#include <stdio.h>
#include <string.h>
int main( void )
{
const char input[] = "111adbhsd111gfhds", *p = input;
const char *const delim = "111";
//remember length of delimiter substring
const size_t delim_length = strlen( delim );
for (;;) //infinite loop, equivalent to "while ( 1 )"
{
//attempt to find next delimiter substring
const char *q = strstr( p, delim );
//break loop if this is last token
if ( q == NULL )
break;
//print token
if ( q == p )
printf( "Found token: <empty>\n" );
else
printf( "Found token: %.*s\n", (int)(q-p), p );
//make p point to start of next token
p = q + delim_length;
}
//print last token
printf( "Found token: %s\n", p );
}
This program has the following output:
Found token: <empty>
Found token: adbhsd
Found token: gfhds
Since the sample input starts with the delimiter "111", the first token is empty. If you don't want empty tokens to be printed, you can simply remove the first printf statement in the code.
This is not a full solution to your problem, as your task seems to consist of multiple input strings instead of only one, and writing to output arrays instead of printing to the screen. In accordance with the community guidelines for homework questions, I will not provide a full solution to your problem at this time. Instead, for now, I have only provided a solution to the problem that you stated that you had trouble with (which was using strtok with substring delimiters). If necessary, I can add additional code later.

Related

Using strtok to find pair of token

I am solving this homework problem: Find a pair of adjacent words in the text, such that both words begin in the same letter.
I understand that I need to use strtok function to solve this problem.
#include <string.h>
#include <stdio.h>
#include <conio.h>
int main(void) {
char testString[] = "In the end, we will remember not the words of our enemies, but the silence of our friends";
char *context = testString;
const char *token = strtok_s(testString, ", ", &context);
while (token) {
token = strtok_s(NULL, ", ", &context);
printf(" %s\n", token);
}
_getch();
}
In that case I have two question:
I don't understand why printf starting print from the second word?
What I need to do next to find word pair, how I can get access to letters of token?
You want to find two consecutive tokens which have the same initial character, right?
So you need to store the previous token when retrieving a next one, so that you can compare their initial characters and possibly print them.
Edited: your use of strtok_s seems incorrect. I fixed my mistake in the code below and replaced a wrong use of strtok_s with a correct use of strtok.
#include <string.h>
#include <stdio.h>
int main(void) {
char testString[] = "In the end, we will remember not the words of our enemies, but the silence of our friends";
const char *token_prev = strtok(testString, ", ");
const char *token_next = strtok(NULL, ", ");
while (token_next) {
if (token_next[0] == token_prev[0]) {
printf(" %s %s\n", token_prev, token_next);
// break; // to print the first pair only
}
token_prev = token_next;
token_next = strtok(NULL, ", ");
}
}
See it working at GodBolt: https://godbolt.org/z/YzjcPKrq6
This will iterate through the whole input string and print all pairs found. If you add a break; after printf() under if() then it will print the first pair only.
printf starts printing from the second word because you never print the first token, i.e. the one you've obtained from the initial call to strtok_s before entering the loop.
Token is a regular C string. Its initial letter is token[0], a char. You can store it in a separate char variable, and carry it over into the next iteration of the loop.
Since the words could be in mixed case, you should probably use toupper or tolower when storing and comparing the initial characters.
You extracted the first word in this statement
const char *token = strtok_s(testString, ", ", &context);
but you did not print it. You are starting to print words in the while loop after the preceding call of strtok_s within the loop.
You need two pointers that will point to adjacent extracted strings and using these pointers you can compare first letters of the strings.
Here is a demonstrative program (for simplicity I am using strtok instead of strtok_s)
#include <stdio.h>
#include <string.h>
int main(void)
{
char testString[] = "In the end, we will remember not the words "
"of our enemies, but the silence of our friends";
char *first_word = NULL;
char *second_word = NULL;
const char *delim = ", ";
if ( ( first_word = strtok( testString, delim ) ) != NULL )
{
while ( ( second_word = strtok( NULL, delim ) ) != NULL &&
*first_word != *second_word )
{
first_word = second_word;
}
}
if ( second_word != NULL )
{
printf( "%s <-> %s\n", first_word, second_word );
}
return 0;
}
The program output is
we <-> will
If you want to output all such pairs of words then the program can look the following way
#include <stdio.h>
#include <string.h>
int main(void)
{
char testString[] = "In the end, we will remember not the words "
"of our enemies, but the silence of our friends";
char *first_word = NULL;
char *second_word = NULL;
const char *delim = ", ";
if ( ( first_word = strtok( testString, delim ) ) != NULL )
{
while ( ( second_word = strtok( NULL, delim ) ) != NULL )
{
if ( *first_word == *second_word )
{
printf( "%s <-> %s\n", first_word, second_word );
}
first_word = second_word;
}
}
return 0;
}
The program output is
we <-> will
of <-> our
of <-> our
However instead of using strtok or strtok_s it is much better to use an approach based on the functions strspn and strcspn. In this case you can process constant strings.

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.

Why I can't print first/last character right?

My output string needs to be palindrom of the input string. It works almost perfect but I am having problem with first character of the input string, my new string won't print it (in essence my new string won't print last character). Also strrev() does not work on Ubuntu so i need to do this without using that function.
#include <stdio.h>
#include <string.h>
int main(void){
int i,j=0;
char input_str[10];
char new_str[10];
printf("Enter characters:\n");
gets(input_str);
for(i=strlen(input_str)-1;i>0;i--){
new_str[j]=input_str[i];
j++;
}
printf("Output:\n");
printf("%s", new_str);
return 0;
}
For starters the function gets is unsafe function and is not supported by the C Standard.
You should use the standard C function fgets.
There are two problems with your code. The first one is in this loop
for(i=strlen(input_str)-1;i>0;i--){
new_str[j]=input_str[i];
j++;
}
the index i equal to 0 is skipped from using it to copy the corresponding character of the source string.
The second one is the destination array is not appended with the terminating zero character.
Here is a demonstrative program that shows how a function that makes a reversed copy of a source string can be implemented.
#include <stdio.h>
#include <string.h>
char * reverse_copy( char *dsn, const char *src )
{
size_t n = strlen( src );
size_t i = 0;
for ( ; i < n; i++ )
{
dsn[i] = src[n - i - 1];
}
dsn[i] = '\0';
return dsn;
}
int main(void)
{
enum { N = 10 };
char input_str[N] = "";
char new_str[N];
printf( "Enter a string (less than %zu symbols): ", ( size_t )N );
fgets( input_str, N, stdin );
input_str[ strcspn( input_str, "\n" ) ] = '\0';
printf( "\"%s\"\n", input_str );
printf( "\"%s\"\n", reverse_copy( new_str, input_str ) );
return 0;
}
The program output might look for example the following way
Enter a string (less than 10 symbols): Hello
"Hello"
"olleH"
i is never zero. That is why the first character (input_str[0]) is ignored.

What has strtok been replaced with? [duplicate]

#include <stdio.h>
int
main() {
char string[] = "my name is geany";
int length = sizeof(string)/sizeof(char);
printf("%i", length);
int i;
for ( i = 0; i<length; i++ ) {
}
return 0;
}
if i want to print "my" "name" "is" and "geany" separate then what do I do. I was thinking to use a delimnator but i dont know how to do it in C
start with a pointer to the begining of the string
iterate character by character, looking for your delimiter
each time you find one, you have a string from the last position of the length in difference - do what you want with that
set the new start position to the delimiter + 1, and the go to step 2.
Do all these while there are characters remaining in the string...
I needed to do this because the environment was working in had a restricted library that lacked strtok. Here's how I broke up a hyphen-delimited string:
b = grub_strchr(a,'-');
if (!b)
<handle error>
else
*b++ = 0;
c = grub_strchr(b,'-');
if (!c)
<handle error>
else
*c++ = 0;
Here, a begins life as the compound string "A-B-C", after the code executes, there are three null-terminated strings, a, b, and c which have the values "A", "B" and "C". The <handle error> is a place-holder for code to react to missing delimiters.
Note that, like strtok, the original string is modified by replacing the delimiters with NULLs.
This breaks a string at newlines and trims whitespace for the reported strings. It does not modify the string like strtok does, which means this can be used on a const char* of unknown origin while strtok cannot. The difference is begin/end are pointers to the original string chars, so aren't null terminated strings like strtok gives. Of course this uses a static local so isn't thread safe.
#include <stdio.h> // for printf
#include <stdbool.h> // for bool
#include <ctype.h> // for isspace
static bool readLine (const char* data, const char** beginPtr, const char** endPtr) {
static const char* nextStart;
if (data) {
nextStart = data;
return true;
}
if (*nextStart == '\0') return false;
*beginPtr = nextStart;
// Find next delimiter.
do {
nextStart++;
} while (*nextStart != '\0' && *nextStart != '\n');
// Trim whitespace.
*endPtr = nextStart - 1;
while (isspace(**beginPtr) && *beginPtr < *endPtr)
(*beginPtr)++;
while (isspace(**endPtr) && *endPtr >= *beginPtr)
(*endPtr)--;
(*endPtr)++;
return true;
}
int main (void) {
const char* data = " meow ! \n \r\t \n\n meow ? ";
const char* begin;
const char* end;
readLine(data, 0, 0);
while (readLine(0, &begin, &end)) {
printf("'%.*s'\n", end - begin, begin);
}
return 0;
}
Output:
'meow !'
''
''
'meow ?'
use strchr to find the space.
store a '\0' at that location.
the word is now printfable.
repeat
start the search at the position after the '\0'
if nothing is found then print the last word and break out
otherwise, print the word, and continue the loop
Reinventing the wheel is often a bad idea. Learn to use implementation functions is also a good training.
#include <string.h>
/*
* `strtok` is not reentrant, so it's thread unsafe. On POSIX environment, use
* `strtok_r instead.
*/
int f( char * s, size_t const n ) {
char * p;
int ret = 0;
while ( p = strtok( s, " " ) ) {
s += strlen( p ) + 1;
ret += puts( p );
}
return ret;
}

c, delete words which contain digits from a string

I need to delete all words that contain digits from the string.
E.g. if input is abdgh 67fgh 32ghj hj dfg43 11 fg, output should be abdgh hj fg.
I thought of using while( text[i] != ' '), but I don't know how to continue it for the rest of the string (after the first whitespace).
I don't have any other idea, and couldn't find anything by googling. Please, help me!
Here, i gave it a try. Works just fine for me. I tried to explain the logic throughout the code via comments. Hope it helps.
#include <stdio.h>
#include <string.h>
int containsNum(char * str);
int main()
{
char str[] = "abdgh 67fgh 32ghj hj dfg43 11 fg"; // input string
char newstr[100] = ""; //new string to create with filtered data
char * pch; //temp string to use in strtok
printf("given string : %s\n",str );
pch = strtok (str," ");
while (pch != NULL)
{
if(!containsNum(pch))// creation of new string with strcat
{ // if the current word not contains any number
strcat(newstr,pch);
strcat(newstr," "); //adding a space between words for readability
}
pch = strtok (NULL, " ");
}
printf("modified string : %s\n", newstr );
return 0;
}
//function containsNum
//gets a string and checks if it has any numbers in it
//returns 1 if so , 0 otherwise
int containsNum(char * str)
{
int i,
size =strlen(str),
flag=0;
for(i=0; i<size ; ++i)
{
if((int)str[i] >=48 && (int)str[i] <=57 ){
flag =1;
break;
}
}
return flag;
}
Regards
Algorithm:
1-You will have to break your input string into smaller components which are also called as tokens. For example: for the string abdgh 67fgh 32ghj hj dfg43 11 fg the tokens could be abdgh, 67fgh, 32ghj, hj, dfg43, 11 and fg.
2- These smaller strings or tokens can be formed using the strtok function which is defined as
char * strtok ( char * str, const char * delimiters );. Thestr in the first argument is the input sting which in the code presented below is string1. The second argument called the delimiters is what actually defines when to divide the input string into smaller pieces(tokens).
For instance, a whitespace as a delimiter will divide the input string whenever a whitespace is encountered, which is how the string is being divided in the code.
3-Since, your program needs to delete those words in the input string which contain digits we can use the isdigit() function to check exactly that.
WORKING CODE:
#include <cstring>
#include <ctype.h>
#include<stdio.h>
int main ()
{
char output[100]="";
int counter;
int check=0; /* An integer variable which takes the value of "1" whenever a digit
is encountered in one of the smaller strings or tokens.
So, whenever check is 1 for any of the tokens that token is to be ignored, that is,
not shown in the output string.*/
char string1[] = "abdgh 67fgh 32ghj hj dfg43 11 fg";
char delimiters[] = " ";//A whitespace character functions as a delimiter in the program
char * token;//Tokens are the sub-strings or the smaller strings which are part of the input string.
token=strtok(string1,delimiters);/*The first strktok call forms the first token/substring which for the input
given would be abdgh*/
while(token!=NULL)/*For the last substring(token) the strtok function call will return a NULL pointer, which
also indicates the last of the tokens(substrings) that can be formed for a given input string.
The while loop finishes when the NULL pointer is encountered.*/
{
for(counter=0;counter<=strlen(token)-1;counter++)/*This for loop iterates through each token element.
Example: In case of abdgh, it will first check for 'a',
then 'b', then 'd' and so on..*/
{
if(isdigit((int)token[counter])>0)/*This is to check if a digit has been encountered inside a token(substring).
If a digit is encountered we make check equal to 1 and break our loop, as
then that token is to be ignored and there is no real need to iterate
through the rest of the elements of the token*/
{
check=1;
break;
}
}
if(check==1) /* Outside the for loop, if check is equal to one that means we have to ignore that token and
it is not to be made a part of the output string. So we just concatenate(join) an
empty string ( represented by " " )with the output string*/
{
strcat(output,"");
check=0;
}
else /*If a token does not contain any digit we simply make it a part of the output string
by concatenating(joining) it with the output string. We also add a space for clarity.*/
{
strcat(output,token);
strcat(output," ");
}
token = strtok( NULL, delimiters ); /*This line of code forms a new token(substring) every time it is executed
inside the while loop*/
}
printf( "Output string is:: %s\n", output ); //Prints the final result
return 0;
}
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
char *filter(char *str){
char *p, *r;
p = r = str;
while(*r){
char *prefetch = r;
bool contain_digit = false;
while(!isspace(*prefetch) && *prefetch){
if(contain_digit)
++prefetch;
else if(isdigit(*prefetch++))
contain_digit = true;
}
if(contain_digit){
r = prefetch;
}else {
while(r < prefetch){
*p++ = *r++;
}
}
if(!*r)
break;
if(p[-1] == *r)
++r;
else
*p++ =*r++;
}
*p = '\0';
return str;
}
int main(void) {
char text[] = "abdgh 67fgh 32ghj hj dfg43 11 fg";
printf("%s\n", filter(text));//abdgh hj fg
return 0;
}

Resources