How do I remove duplicate vowels from a string?

Viewed 974

Question: Define an int function that removes all consecutive vowel repetitions from a string. The function should return the number of vowels removed and present the string without duplicates.

I am PT so Vogais is Vowels; Digite uma String is Write one String. A String sem duplicados fica assim ' %s ' e foram retiradas %d vogais is The string without duplicates is ' %s ' and where removed %d vowels.

Explanation: In portuguese we have some words with two consecutive vowels like: coordenador, coordenação (chqrlie example). But in thouse cases should be ignored in the context of this problem.

Problem: When I test a string like 'ooooo' it says the string without duplicate vogals is 'oo' and where removed 3 vowels. But it should be 'o' and 4 vowels removed. Another example with error is 'Estaa e umaa string coom duuuplicadoos', I am getting ' Esta e uma string com duplcdos ' and 8 vowels removed.

Note: This is a simple question so there isn't need to complicate. It only askes the consecutive duplicate vowels. The cases 'oOoO' -> 'oO' ,'abAb'->'abAb','abab' -> 'ab','aba'-> 'aba',... are in another chapter XD.

int Vogais(char *s) {
    if (*s == 'A' || *s == 'a' || *s == 'E' || *s == 'e'
     || *s == 'I' || *s == 'i' || *s == 'O' || *s == 'o'
     || *s == 'U' || *s == 'u') return 1;
    return 0;
}

int retiraVogaisRep(char *s) {
    int res = 0;
    for (int i = 0; i < strlen(s); i++) {
        for (int j = i + 1; s[j] != '\0'; j++) {
            if (s[i] == s[j] && Vogais(&s[j]) == 1) {
                res++;
                for (int k = j; s[k] != '\0'; k++) {
                    s[k] = s[k + 1];
                }
            }
        }
    }
    return res;
}

int main() {
    char s[38];
    printf("Digite uma String:\n");
    scanf("%[^\n]", s);
    int res = retiraVogaisRep(s);
    printf("A String sem duplicados fica assim ' %s ' e foram retiradas %d vogais.\n", s, res);
    return 0;
}
5 Answers

Your code is too complicated: there is no need for nested loops for this task and you do not set the null terminator when shortening the string.

Here is a simpler version:

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

int retiraVogaisRep(char *s) {
    int i, j;      // use 2 running indices
    char c, last = 0;
    for (i = j = 0; (c = s[i]) != '\0'; i++) {
        if (c != last || !strchr("aeiouAEIOU", c))
            s[j++] = last = c;
    }
    s[j] = '\0';   // set the null terminator
    return i - j;  // return the number of bytes removed
}

int main() {
    char s[100];

    printf("Digite uma String:\n");

    // read the user input safely with `fgets()`
    if (!fgets(s, sizeof s, stdin))
        return 1;

    // strip the trailing newline if any
    s[strcspn(s, "\n")] = '\0';

    // remove duplicate consecutive vowels
    int res = retiraVogaisRep(s);

    printf("A String sem duplicados fica assim ' %s ' e foram retiradas %d vogais.\n", s, res);
    return 0;
}

Remove consecutive duplicate vowels

You should use tolower function from ctype.h to check for vowels, that include the letter 'y', see below working code:

You can store previous character in prev and compare it to the current character, as you are case insensitive you store the tolower version.

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

int Vogais(char c){
    return (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || c == 'y') ;
}

int retiraVogaisRep (unsigned char *s){
    if (*s == NULL)
        return 0;
        
    unsigned char t[256];
    memset(t, 0, sizeof(t));
    int res = 0;
    int j = 0;
    t[0] = s[0];
    char prev = tolower(s[0]);
    int len = strlen(s);

    for (int i = 1; i < len; i++) {
        char c = tolower(s[i]);
        if (Vogais(c) && c == prev)
            ++res;
        else
            t[j++] = s[i];
        prev = c;

    }
    memcpy(s, t, sizeof(t));
    return res;
}

int main(){
    char s[256];
    printf("Digite uma String:\n");
    scanf("%255[^\n]", s);
    int res = retiraVogaisRep(s);
    printf("Da String ' %s ' podem ser retiradas %d vogais.\n", s,res);
    return 0;
}

The question tag is C, but I will not post the actual code here.

The pseudocode:

function is_vowel(int c) {...}

start loop c = <src>
 if next_char is past the last char then quit loop;
 if is_vowel(c) and c == next_char and is_vowel(next_char)
  then continue;
 else
  copy c to <dst>

You should elaborate on this, as the above is possibly having small issues. Nevertheless, I think this answer is somewhat shorter and gives an insight.

Update

The above is definitly have an issue, in that the next char does not copied to the output. The mistake is easy to correct, so I will leave it up to OP.

Update

Edited above code to indicate that OP wants to remove only identical duplicates. So, the case of a charcter is important.

Rather than a triple nested loop, consider a single walk down the string, looking for repeats.

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

int Vogais(unsigned char s) {
    if (s == 'A' || s == 'a' || s == 'E' || s == 'e'
     || s == 'I' || s == 'i' || s == 'O' || s == 'o'
     || s == 'U' || s == 'u') return 1;
    return 0;
}

int retiraVogaisRep(char *s) {
  unsigned char *us = (unsigned char *) s;
  unsigned char *dest = us;
  int res = 0;
  int prior = EOF;
  while (*us) {
    while (toupper(*us) == prior) {
      us++;
      res++;
    }
    prior = Vogais(*us) ? toupper(*us) : EOF;
    *dest++ = *us++;
  }
  *dest = '\0';
  return res;
}

int main() {
  char buf[100] = "OoFreedaa";
  printf("%d\t", retiraVogaisRep(buf));
  printf("<%s>\n", buf);
  return 0;
}

Output

3   <OFreda>

Retaining the uppercase, using the Kernighan-copy


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

size_t remove_duplicate_vowels(char *str)
{
int old,new;
size_t dst,src;

old = 0;
for(dst=src=0; str[dst] = str[src]; old=new, src++ ) {
        new = toupper( str[dst] );
        if ( !strchr( "AEIOU",  new )) { // Not a vowel
                dst++; continue;
                }
        if ( new != old ) { // Not a repetition
                dst++; continue;
                }
        }

return src - dst;
}

int main(int argc, char **argv)
{
char test[] = "Aaa bbBb CccCC d eEeee!";
char *arg;
size_t ret;

arg = argv[1] ?  argv[1] : test;

ret = remove_duplicate_vowels(arg);

fprintf(stderr, "[%zu]: %s\n", ret, arg);

return 0;
}
Related