1

My teacher requested a C function with this characteristics:

int removeVowels(char *s)
{
    ...
}
  • Input (Example) : "Estaa e umaa string coom duuuplicadoos"

  • Output : "Esta e uma string com duplicados"

The program should also output the numbers of letters removed.

All help would be appreciated.

Attempt:

int aux[1000];
int i = 0;

int retiraVogaisRep (char *s){
    if (*s == '\0'){
        return 0;
    }
    else{
        if ((*s == 'A' || *s == 'E' || *s == 'I' || *s == 'O' || *s == 'U' || *s == 'a' || *s == 'e' || *s == 'i' || *s == 'o' || *s == 'u') && aux[i] != *s){
            i++;
            aux[i] = *s;
            return retiraVogaisRep(s + 1);
        }
        else if ((*s == 'A' || *s == 'E' || *s == 'I' || *s == 'O' || *s == 'U' || *s == 'a' || *s == 'e' || *s == 'i' || *s == 'o' || *s == 'u') && aux[i] == *s){
            i++;
            aux[i] = *s;
            *s = '';
            return 1 + retiraVogaisRep(s + 1);
        }
        else{
            return retiraVogaisRep(s + 1);
        }
    }
}

Attemp 2 (works but is there a easier way?) :

char final[1000];
char aux[1000];
int k = 0;
int i = 0;
int y = 0;

int retiraVogaisRep (char *s){

    if (*s == '\0'){
        while (k < y){
            *(s - i) = final[k];
            i--;
            k++;
        }
        while (i >= 0){
            *(s - i) = final[1000];
            i--;
        }
        return 0;
    }
    else{
        if ((*s == 'A' || *s == 'E' || *s == 'I' || *s == 'O' || *s == 'U' || *s == 'a' || *s == 'e' || *s == 'i' || *s == 'o' || *s == 'u') && aux[i] != *s){
            i++;
            aux[i] = *s;
            final[y] = *s;
            y++;
            return retiraVogaisRep(s + 1);
        }
        else if ((*s == 'A' || *s == 'E' || *s == 'I' || *s == 'O' || *s == 'U' || *s == 'a' || *s == 'e' || *s == 'i' || *s == 'o' || *s == 'u') && aux[i] == *s){
            i++;
            aux[i] = *s;
            return 1 + retiraVogaisRep(s + 1);
        }
        else{
            final[y] = *s;
            y++;
            i++;
            return retiraVogaisRep(s + 1);
        }
    }
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Zagueiro
  • 11
  • 3
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/230320/discussion-on-question-by-zagueiro-is-there-a-way-to-delete-a-repeated-character). – Samuel Liew Mar 24 '21 at 13:39
  • Related: https://stackoverflow.com/questions/66790357/how-do-i-remove-duplicate-vowels-from-a-string – Jerry Jeremiah Mar 25 '21 at 22:42

3 Answers3

3

This is a possible solution:

    int removeVowels(char *s)
    {
        char *src = s;
        char *dst = s;

        while (*dst != '\0')
        {
            switch (* ++ src)
            {
            case 'A': case 'a':
            case 'E': case 'e':
            case 'I': case 'i':
            case 'O': case 'o':
            case 'U': case 'u':
                if (* src != * dst)
                    * ++ dst = * src;
                break;

            default:
                * ++ dst = * src;
                break;
            }
        }

        return src - dst;
    }

First, the first character of the input string is the first character of output -- even if it's a vowel, it certainly is not a duplicate yet!

Then we enter a loop. The loop will work until the resulting string is terminated -- so while the character pointed at by the dst pointer is not zero, do iterate.

In every iteration we advance the src pointer and fetch a character pointed at. If it is a vowel we test if it's same as the most recently accepted output character (pointed at by dst); if so, we skip it, otherwise we append it to the result (by advancing the dst pointer and copying the character.

OTOH if the character is not a vowel, we copy it with no more conditions.

Once src pointer reaches the end of the string, the zero byte (a string terminator) is copied, and the loop exits.

At this moment, src points at the end of the source string and dst points at the end of the resulting string (which starts at the same point where the source string was starting, but it can be shorter now than the source).
So the difference of pointers src - dst is exactly the number of characters (vowels) skipped.

Try it here: https://onlinegdb.com/ryNzvTUVu

CiaPan
  • 9,381
  • 2
  • 21
  • 35
2
int isVowel(char ch)
{
    if (ch >= 'A' && ch <= 'Z')
        ch = (ch - 'A') + 'a';
    return (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u');
} 

int removeVowels(char *s)
{
    int removed = 0;

    if (s)
    {
        while (*s != '\0')
        {
            char ch = *s++;

            if (isVowel(ch) && (*s == ch))
            {
                char *src = s, *dst = s;

                do {
                   ++src;
                   ++removed;
                }
                while (*src == ch);

                while (*src != '\0') {
                    *dst++ = *src++;
                }

                *dst = '\0';
            }
        }
    }

    return removed;
}

Demo

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
1

The other answers (two at the time of posting this) both give excellent (and efficient) solutions. Here, I offer another – less efficient but, hopefully, simpler and clearer.

First, let's define a function to test if a character is a vowel. Whenever you end up doing something more than once in a program, or if (even though you only do it once) you get long, 'ugly' lines or blocks of code, then you should consider moving that code into a function. You never know when you might need it again and, if you do, then it's already a done deed.

int isVowel(char c)
{
    static char* vowels = "AEIOUaeiou"; // Making this "static" cause initialization only once
//  static char* vowels = "AEIOUWYaeiouwy"; // Alternative for Welsh people!
    for (char* cp = vowels; *cp; ++cp) {
        if (c == *cp) return 1; // Matched a vowel, we can return without further loops
    }
    return 0; // Loop finished without matching, so it's not a vowel
}

Next, the function to remove duplicate vowels. This version just runs a simple loop through the given string, copying the 'source' to the 'destination' if the removal condition isn't met. We can safely do this by overwriting the string itself, as we will never need to 'go back' and look at characters in that original string more than once.

Note, also, that we will be overwriting characters with themselves, until we have found at least one character to skip – but this is a case of sacrificing a modicum of efficiency to maintain code simplicity. There are other places where adding some complexity to the code would also make it more efficient … I'll leave these as the proverbial "exercise for the reader!"

int removeVowels(char* string)
{
    int skipped = 0; // Keep a running tally of how many we removed
    char *src = string, *dst = string; // Use 2 pointers (source and destination): both start at beginning of string
    char previous = '?'; // Keep track of last letter - start with an 'impossible' value

    while (*src) // Loop until we find the nul terminator
    {
        if (!isVowel(*src) || *src != previous) { // Not a vowel or not same as last ...
            *dst++ = *src;   // ... so copy it to 'new' string and increment destination pointer
        }
        else {               // Otherwise, all we do is incrememnt our removals count.
            ++skipped;
        }
        previous = *src++;   // Change our saved last letter, then increment the source pointer
    }

    *dst = '\0'; // Finally, add the nul-terminator to our modified string
    return skipped;
}

Finally, a short main program to test the above code with the example input provided:

#include <stdio.h>
int main()
{
    char test[] = "Estaa e umaa string coom duuuplicadoos";
    int lost = removeVowels(test);
    printf("Result: %s (removed %d vowels)\n", test, lost);
    return 0;
}
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • That's a good answer - I think simpler and clearer has definite advantages. One thing I would do is: instead of `if (!isVowel(*src) || *src != previous)` I would have used the positive logic `if (isVowel(*src) && *src == previous)` and swapped the then and else branches because I think that makes more sense to beginners. Just an observation... – Jerry Jeremiah Mar 23 '21 at 02:35
  • @JerryJeremiah A very reasonable point. Perhaps it's my Welsh origins (see edit) that tilt me to use negative logic first. – Adrian Mole Mar 23 '21 at 02:38