Home > Software design >  How to separate a string by spaces and save the separated words regardless?
How to separate a string by spaces and save the separated words regardless?

Time:05-21

I have a program that separates words by spaces. I need to count which words in the text contain 4 different vowels. It didn't seem complicated, until I realized that I know how to save the divided words of the function (strtok) that returns the separated words, and of course, I can't count a single word because the function only prints. I don't know how to save the word individually to calculate how many vowels it contains and continue with the other words, one by one.

#include <stdio.h>
#include <string.h>

#define MAX 100

int main() {
    char phase[MAX];
    char temp [50];
    char delim[] = " ";
    
    printf("Ingrese un texto corto: ");
    gets(phase); //Short text with spaces
    printf("\n");
    
    for (i = 0; x < phase[x] != '\0';   x) {
        if (phase[x] == ' ' || phase[x] == '\t' || phase[x] == '\v') {
            //Detect space.
        }
    }
    
    char *ptr = strtok(phase, delim);
    
    while (ptr != NULL) {
        printf("%s\n", ptr); //I need to keep all the words separate.
        
        ptr = strtok(NULL, delim);
    }

    return 0;
}

Result:

Ingrese un texto corto: Ana come en el refrigerador.

Ana
come
en
el
refrigerador.

CodePudding user response:

I believe this code will solve the task. It's tempting to use strtok() again to search for vowels, but that would erase any information about word bounds from strtok's internal memory. So, instead, use strpbrk() (docs and more docs)

#include <stdio.h>
#include <string.h>

#define MAX 100

int main() {
    char text[MAX];

    // all isspace() characters for "C" locale
    char delimiters[] = " \t\n\v\f\r";

    char vowels[] = "aeiou";

    printf("Input a string of text: ");
    // replaced unsafe gets() with more safe fgets()
    fgets(text, sizeof(text), stdin);

    char* word = strtok(text, delimiters);
    while (word != NULL) {
        // strpbrk() does roughly the same thing as strtok(), but it doesn't
        // modify a string nor does it remember anything on future calls
        char* ptr_to_vowel = word;
        int count = 0;
        while (NULL != (ptr_to_vowel = strpbrk(ptr_to_vowel, vowels))) {
            count  ;

            // otherwise we'd stay on the same vowel
            ptr_to_vowel  ;
        }
        printf("found %d vowels in %s\n", count, word);
        word = strtok(NULL, delimiters);
    }
    return 0;
}

CodePudding user response:

A few issues:

  1. The for loop for counting spaces is incorrect.
  2. We should have a separate function to count vowels.
  3. Never use gets (use fgets instead).
  4. The code did not preserve the original buffer as the code comments suggested.

I need to count which words in the text contain 4 different vowels.

So, we can only count unique vowels in a word (e.g.):

  1. fleece has only 1 unique vowel and not 3.
  2. great has 2 vowels
  3. greet has 1 vowel
  4. incombustible has 4 [unique] vowels and not 5.

It's not totally clear, but I interpret this to mean that a candidate word has at least 4 unique vowels (i.e. it could have 5)


I had to refactor quite a bit of the code. It is annotated:

#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <ctype.h>

#define MAX 100

// vcount -- count _unique_ vowels
// RETURNS: number of _unique_ vowels
int
vcount(const char *str)
{
    const char *vowels = "aeiou";
    int vfreq[5] = { 0 };
    int vsum = 0;

    // loop through all chars in string
    for (int chr = *str  ;  chr != 0;  chr = *str  ) {
        // get lower case
        chr = tolower((unsigned char) chr);

        // is it a vowel?
        const char *vptr = strchr(vowels,chr);
        if (vptr == NULL)
            continue;

        // get index into frequency table
        ptrdiff_t vidx = vptr - vowels;

        // have we seen it before?
        if (vfreq[vidx])
            continue;

        // mark as already seen
        vfreq[vidx] = 1;

        // count new unique vowel
          vsum;
    }

    return vsum;
}

int
main(void)
{
    char phrase[MAX];
    char temp[MAX];
    const char *delim = " \t\v";

    printf("Ingrese un texto corto: ");
    // Short text with spaces
// NOTE/BUG: _never_ use gets
#if 0
    gets(phrase);
#else
    fgets(phrase,sizeof(phrase),stdin);
#endif
    printf("\n");

// NOTE/BUG: loop condition is incorrect
#if 0
    for (i = 0; x < phrase[x] != '\0';   x) {
        if (phrase[x] == ' ' || phrase[x] == '\t' || phrase[x] == '\v') {
            // Detect space.
        }
    }
#else
    int space_count = 0;
    for (int i = 0; phrase[i] != '\0';   i) {
        switch (phrase[i]) {
        case ' ':
        case '\t':
        case '\v':
              space_count;
            break;
        }
    }
    printf("Spaces: %d\n",space_count);
#endif

    // I need to keep all the words separate.
#if 0
    char *ptr = strtok(phrase, delim);
#else
    strcpy(temp,phrase);
    char *ptr = strtok(temp, delim);
#endif

    while (ptr != NULL) {
#if 0
        printf("%s\n", ptr);
#else
        printf("%s -- has enough vowels: %s\n",
            ptr,(vcount(ptr) >= 4) ? "Yes" : "No");
#endif

        ptr = strtok(NULL, delim);
    }

    return 0;
}

In the above code, I used cpp conditionals to denote old vs new code:

#if 0
// old code
#else
// new code
#endif

#if 1
// new code
#endif

For the input:

Ana come en el refrigerador.

Here is the program output:

Ingrese un texto corto:
Spaces: 4
Ana -- has enough vowels: No
come -- has enough vowels: No
en -- has enough vowels: No
el -- has enough vowels: No
refrigerador. -- has enough vowels: Yes

CodePudding user response:

Instead of splitting words and then count vowels inside them, you can count vowels and upon a delimiter, check the vowel count and reset the count. This way, you do not need to modify the string. You actually do not even need an array to store the string: you can just read one byte at a time.

Here is a modified version:

#include <stdio.h>

int main() {
    int c;
    int mask = 0;
    int vowels = 0;
    int matches = 0;
    int done = 0;
    
    printf("Ingrese un texto: ");
    while (!done) {
        switch (getchar()) {
          case EOF:
          case '\n':
            if (vowels >= 4)
                matches  ;
            vowels = mask = 0;
            done = 1;
            break;
          case ' ':
          case '\t':
          case '\n':
          case '\v':
          case '\f':
          case '\r':
            if (vowels >= 4)
                matches  ;
            vowels = mask = 0;
            break;
          case 'a':
          case 'A':
            if (!(mask & 1)) {
                mask |= 1;
                vowels  ;
            }
            break;
          case 'e':
          case 'E':
            if (!(mask & 2)) {
                mask |= 2;
                vowels  ;
            }
            break;
          case 'i':
          case 'I':
            if (!(mask & 4)) {
                mask |= 4;
                vowels  ;
            }
            break;
          case 'o':
          case 'O':
            if (!(mask & 8)) {
                mask |= 8;
                vowels  ;
            }
            break;
          case 'u':
          case 'U':
            if (!(mask & 16)) {
                mask |= 16;
                vowels  ;
            }
            break;
        }
    }
    printf("%d\n", matches);
    return 0;
}
  •  Tags:  
  • c
  • Related