简体   繁体   中英

Rotate words around vowels in C

I am trying to write a program that reads the stdin stream looking for words (consecutive alphabetic characters) and for each word rotates it left to the first vowel (eg "friend" rotates to "iendfr") and writes this sequence out in place of the original word. All other characters are written to stdout unchanged.

So far, I have managed to reverse the letters, but have been unable to do much more. Any suggestions?

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define MAX_STK_SIZE 256

char stk[MAX_STK_SIZE];
int tos = 0; // next available place to put char

void push(int c) {
    if (tos >= MAX_STK_SIZE) return;
    stk[tos++] = c;
}

void putStk() {
    while (tos >= 0) {
        putchar(stk[--tos]);
    }
}

int main (int charc, char * argv[]) {
    int c;
    do {
        c = getchar();
        if (isalpha(c) && (c == 'a' || c == 'A' || c == 'e' || c ==         'E' || c == 'i' || c == 'o' || c == 'O' || c == 'u' || c == 'U')) {
            push(c);
        } else if (isalpha(c)) {
            push(c);
        } else {
            putStk();
            putchar(c);
        }
    } while (c != EOF);
}

-Soul

I am not going to write the whole program for you, but this example shows how to rotate a word from the first vowel (if any). The function strcspn returns the index of the first character matching any in the set passed, or the length of the string if no matches are found.

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

void vowelword(const char *word)
{
    size_t len = strlen(word);
    size_t index = strcspn(word, "aeiou");
    size_t i;
    for(i = 0; i < len; i++) {
        printf("%c", word[(index + i) % len]);
    }
    printf("\n");
}

int main(void)
{
    vowelword("friend");
    vowelword("vwxyz");
    vowelword("aeiou");
    return 0;
}

Program output:

iendfr
vwxyz
aeiou

There are a number of ways your can approach the problem. You can use a stack, but that just adds handling the additional stack operations. You can use a mathematical reindexing, or you can use a copy and fill solution where you copy from the first vowel to a new string and then simply add the initial characters to the end of the string.

While you can read/write a character at a time, you are probably better served by creating the rotated string in a buffer to allow use of the string within your code. Regardless which method you use, you need to validate all string operations to prevent reading/writing beyond the end of your input and/or rotated strings. An example of a copy/fill approach to rotating to the first vowel in your input could be something like the following:

/* rotate 's' from first vowel with results to 'rs'. 
 * if 's' contains a vowel, 'rs' contains the rotated string, 
 * otherwise, 'rs' contais 's'. a pointer to 'rs' is returned
 * on success, NULL otherwise and 'rs' is an empty-string.
 */
char *rot2vowel (char *rs, const char *s, size_t max)
{
    if (!rs || !s || !max)  /* validate params */
        return NULL;

    char *p = strpbrk (s, "aeiou");
    size_t i, idx, len = strlen (s);

    if (len > max - 1) {    /* validate length */
        fprintf (stderr, "error: insuffieient storage (len > max - 1).\n");
        return NULL;
    }

    if (!p) {   /* if no vowel, copy s to rs, return rs */
        strcpy (rs, s);
        return rs;
    }

    idx = p - s;        /* set index offset    */
    strcpy (rs, p);     /* copy from 1st vowel */

    for (i = 0; i < idx; i++)   /* rotate beginning to end */
        rs[i+len-idx] = s[i];

    rs[len] = 0;        /* nul-terminate */

    return rs;
}

Above, strpbrk is used to return a pointer to the first occurrence of a vowel in string 's' . The function takes as parameters a pointer to a adequately sized string to hold the rotated string 'rs' , the input string 's' and the allocated size of 'rs' in 'max' . The parameters are validated and s is checked for a vowel with strpbrk which returns a pointer to the first vowel in s (if it exists), NULL otherwise. The length is checked against max to insure adequate storage.

If no vowels are present, s is copied to rs and a pointer to rs returned, otherwise the pointer difference is used to set the offset index to the first vowel, the segment of the string from the first vowel-to-end is copied to rs and then the preceding characters are copied to the end of rs with the loop. rs is nul-terminated and a pointer is returned.

While I rarely recommend the use of scanf for input, (a fgets followed by sscanf or strtok is preferable), for purposes of a short example, it can be used to read individual strings from stdin . Note: responding to upper/lower case vowels is left to you. A short example setting the max word size to 32-chars (31-chars + the nul-terminating char) will work for all known words in the unabridged dictionary (longest word is 28-chars):

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

enum { BUFSZ = 32 };

char *rot2vowel (char *rs, const char *s, size_t max);

int main (void)
{
    char str[BUFSZ] = {0};
    char rstr[BUFSZ] = {0};

    while (scanf ("%s", str) == 1)
        printf (" %-8s => %s\n", str, rot2vowel (rstr, str, sizeof rstr));

    return 0;
}

Example Use/Output

(shamelessly borrowing the example strings from WeatherVane :)

$ echo "friend vwxyz aeiou" | ./bin/str_rot2vowel
 friend   => iendfr
 vwxyz    => vwxyz
 aeiou    => aeiou

Look it over and let me know if you have any questions. Note: you can call the rot2vowel function prior to the printf statement and print the results with rstr , but since the function returns a pointer to the string, it can be used directly in the printf statement. How you use it is up to you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM