1

I want to write a program that outputs whether a string is styled in pascal case, camel case, snake case, kebab case, or none of them. in the first line, we should take integer n from input. then, in the next n lines, we should take an integer k and then a string with no space in each line. k is the size of the string. here's an example of how each of these case styles look like:

pascal case => HelloWorld
camel case => helloWorld
snake case => hello_world
kebab case => hello-world

e.g: input :

3
11 masterShifu
12 master_shifu
12 MASTER_SHIFU

output:

camel case
snake case
undefined case style

my problem with this program is that I don't know how to find the first letter of each word since there's no space between two different words. this is what i've written so far:

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

int
main()
{
    int n;

    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        int k;

        scanf("%d ", &k);
        char word[k];

        gets(word[k]);
        int count = 0;

        if (isupper(word[0]) == 1) {
            for (int i = 1; i < n; i++) {
                if (isupper(word[i]) == 1) {
                    count++;
                }
            }
            if (count == k)
                printf("Undefined Case Style\n");
            else
                printf("PascalCase\n");
        }
        else {
            int c = 0,
                s = 0,
                count = 0;

            for (int i = 0; i < n; i++) {
                if (word[i] == '-') {
                    c++;
                    printf("kebab-case\n");
                    break;
                }
                else if (word[i] == '_')    // snake case
                {
                    s++;
                    printf("snake_case\n");
                    break;
                }
                else if (isupper(word[i]) == 1) // camel case
                {
                    count++;
                    printf("camelCase\n");
                    break;
                }

            }
            if (c == 0 && s == 0)
                printf("Undefined Case Style\n");
        }
    }
    return 0;
}
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
Fateme
  • 41
  • 4
  • Don't look for spaces. Look for either `_`, `-`, or a letter that's the opposite case of the letter before it. – Barmar Apr 26 '23 at 21:05
  • 1
    [Don't use gets](https://linux.die.net/man/3/gets). It is unsafe and deprecated. Not to mention, you are sending a single character to it `gets(word[k]);` which is meaningless. How did that even compile? Turn on your warnings in whatever compiler you're using, and switch to `fgets`. The beginning of the word will just be the first non-white-space character in the string returned by `fgets`. – Jason Apr 26 '23 at 21:08
  • 2
    I suggest you define more precisely what each means. For instance what is `a-b_c`, `AbC`. A great way to document hard-coding test cases in `main()`. – Allan Wind Apr 26 '23 at 22:07
  • Also remember to skip/trim leading an trailing whitespace c.f. `isspace()`. – Kingsley Apr 26 '23 at 23:53
  • Make yourself some helper functions, `containsUpper( const char *str )`, `containsLower( const char *str )`, `containsLetter( const char *str, char letter )`. A good approach might be to rule-out all the *malformed* combinations first, and per @AllanWind's comment. – Kingsley Apr 26 '23 at 23:59

1 Answers1

1

I suggest you iterate through the input string s then given current character *s and what case found you have found determine if the *s is a valid and what the new found is or you can terminate processing.

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

enum str_case {
    CAMEL,
    KEBAB,
    PASCAL,
    SNAKE,
    UNDEFINED,
};

enum str_case str2str_case(const char *s) {
    enum str_case found = isupper(*s++) ? PASCAL : UNDEFINED;
    for(; *s; s++) {
        if(*s == '-') {
            if(found == KEBAB)
                continue;
            if(found == UNDEFINED) {
                found = KEBAB;
                continue;
            }
            return UNDEFINED;
        }
        if(*s == '_') {
            if(found == SNAKE)
                continue;
            if(found == UNDEFINED) {
                found = SNAKE;
                continue;
            }
            return UNDEFINED;
        }
        if(isupper(*s)) {
            if(found == CAMEL || found == PASCAL)
                continue;
            if(found == UNDEFINED) {
                found = CAMEL;
                continue;
            }
            return UNDEFINED;
        }
        if(!islower(*s))
            return UNDEFINED;
    }
    return found;
}

int main(void) {
    struct test {
        char *input;
        enum str_case expected;
    } tests[] = {
        {"helloWorld", CAMEL},
        {"hello-world", KEBAB},
        {"HelloWorld", PASCAL},
        {"hello_world", SNAKE},
        {"", UNDEFINED},
        {"!", UNDEFINED},
        {"A-b", UNDEFINED},
        {"a_b-c", UNDEFINED},
    };
    for(struct test *t = tests; t < tests + sizeof tests / sizeof *tests; t++) {
        enum str_case got = str2str_case(t->input);
        if(t->expected != got) {
            printf("fail: %s: expected %d but got %d\n", t->input, t->expected, got);
            continue;
        }
        printf("ok\n");
    }
}

and here is the output:

ok
ok
ok
ok
ok
ok
ok
ok

I would then refactor the code with the macro:

#define CHECK(char_predicate, state_predicate, new_state) \
    if((char_predicate)) {\
        if((state_predicate))\
            continue;\
        if(found == UNDEFINED) {\
            found = (new_state);\
            continue;\
        }\
        return UNDEFINED;\
    }

and the function becomes simply:

enum str_case str2str_case(const char *s) {
    enum str_case found = isupper(*s++) ? PASCAL : UNDEFINED;
    for(; *s; s++) {
        CHECK(*s == '-', found == KEBAB, KEBAB);
        CHECK(*s == '_', found == SNAKE, SNAKE);
        CHECK(isupper(*s), found == CAMEL || found == PASCAL, CAMEL);
        if(!islower(*s))
            return UNDEFINED;
    }
    return found;
}

Other than fgets() instead of gets() you didn't seem to have issues with parsing the input format, and generating the expected output format so leaving that as an exercise to reader.

Allan Wind
  • 23,068
  • 5
  • 28
  • 38