在C中将单词从camelCase转换为snake_case

seu*_*ung 3 c computer-science

我想要编码的是,如果我输入camelcase,它应该只打印出camelcase,但是如果包含任何大写字母,例如,如果我输入camelCase,它应该打印出camel_case

下面是我正在研究的一个,但问题是,如果我输入camelCase,它会打印出来camel_ase

有人可以告诉我原因以及如何解决吗?

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

int main() {
    char ch;
    char input[100];
    int i = 0;

    while ((ch = getchar()) != EOF) {
        input[i] = ch;
        if (isupper(input[i])) {
            input[i] = '_';
            //input[i+1] = tolower(ch);
        } else {
            input[i] = ch;
        }
        printf("%c", input[i]);

        i++;
    }
}
Run Code Online (Sandbox Code Playgroud)

小智 5

首先查看您的代码并考虑当有人输入超过 100 个字符的单词时会发生什么 ->未定义行为。如果您使用缓冲区进行输入,则必须始终添加检查,以免该缓冲区溢出

但是,当您直接打印字符时,为什么还需要缓冲区呢?您展示的方法完全没有必要。尝试这个:

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

int main()
{
    int ch;
    int firstChar = 1; // needed to also accept PascalCase
    while((ch = getchar())!= EOF)
    {
        if(isupper(ch))
        {
            if (!firstChar) putchar('_');
            putchar(tolower(ch));

        } else
        {
            putchar(ch);
        }
        firstChar = 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

旁注:我将 的类型更改chint。这是因为getchar()退货的intputchar()isupper()islower()采取int他们都使用的值unsigned char,或EOF。由于char允许签名,在带有 signed 的平台上char,您会得到未定义的行为,以否定的char. 我知道,这有点复杂。解决此问题的另一种方法是在调用将 an 的值作为 an的函数时始终强制char转换为 to 。unsigned charunsigned charint


当你使用一个缓冲,现在也没用吧,你可能有兴趣有一个可能的解决方案充分利用缓冲的:读,写一次一整行。这比为每个单个字符调用一个函数稍微更有效。这是一个这样做的例子:

#include <stdio.h>

static size_t toSnakeCase(char *out, size_t outSize, const char *in)
{
    const char *inp = in;
    size_t n = 0;
    while (n < outSize - 1 && *inp)
    {
        if (*inp >= 'A' && *inp <= 'Z')
        {
            if (n > outSize - 3)
            {
                out[n++] = 0;
                return n;
            }
            out[n++] = '_';
            out[n++] = *inp + ('a' - 'A');
        }
        else
        {
            out[n++] = *inp;
        }
        ++inp;
    }
    out[n++] = 0;
    return n;
}

int main(void)
{
    char inbuf[512];
    char outbuf[1024]; // twice the lenght of the input is upper bound

    while (fgets(inbuf, 512, stdin))
    {
        toSnakeCase(outbuf, 1024, inbuf);
        fputs(outbuf, stdout);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

此版本也避免了isupper()tolower(),但牺牲了可移植性。它只有当字符编码在序列信件和具有前的小写字母的大写字母的作品。对于 ASCII,这些假设成立。请注意,什么被认为是(大写)字母也可能取决于语言环境。上面的程序仅适用于英语中的字母 AZ。