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

时间:2017-06-25 11:08:04

标签: 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++;
    }
}

5 个答案:

答案 0 :(得分:4)

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

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

#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;
    }
}

附注:我将ch的类型更改为int。这是因为getchar()返回intputchar()isupper()islower()获取int并且它们都使用unsigned char的值1}}或EOF。由于允许在带有签名char的平台上对char进行签名,因此您将获得使用否定char调用这些函数的未定义行为。我知道,这有点复杂。解决此问题的另一种方法是,在调用将char的值设为unsigned char的函数时,始终将unsigned char强制转换为int

当你使用缓冲区时,它现在没用了,你可能会感兴趣 一个可以很好地利用缓冲区的解决方案:一次读取和写入一行。这比为每个单个字符调用函数稍微有效一些。这是一个例子:

#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;
}

此版本还避免了isupper()tolower(),但牺牲了可移植性。如果字符编码按顺序包含字母并且在小写字母之前使用大写字母,则有效。对于ASCII,这些假设成立。请注意,被视为(大写)字母的内容也可能取决于区域设置。上述程序仅适用于英文字母A-Z。

答案 1 :(得分:0)

您的代码中存在两个问题:

  • 您在if的每个分支中插入一个字符,而其中一个字符应插入两个字符,
  • 您可以随意打印字符,但第一个分支应该同时打印_ch

您可以通过在i插入时增加i++,并在结尾处打印整个字来解决此问题:

int ch; // <<== Has to be int, not char
char input[100];
int i = 0;

while((ch = getchar())!= EOF && (i < sizeof(input)-1)) {
    if(isupper(ch)) {
        if (i != 0) {
            input[i++] = '_';
        }
        ch = tolower(ch);
    }
    input[i++] = ch;
}
input[i] = '\0'; // Null-terminate the string
printf("%s\n", input);

Demo.

答案 2 :(得分:0)

我不知道如何在C中编码,但我认为你应该做这样的事情。

if(isupper(input[i]))
{
    input[i] = tolower(ch);
    printf("_");

} else
{
    input[i] = ch;
}

答案 3 :(得分:0)

您的代码中存在多个问题:

  • ch被定义为char:如果c未定义为int,则无法正确测试文件结尾。 getc()可以返回unsigned char类型的所有值加上特殊值EOF,这是负数。将ch定义为int

  • 您将字节存储到数组input并使用isupper(input[i])isupper()仅针对getc()返回的值定义,如果此类型在目标系统上签名,则不会针对char类型的潜在负值定义。使用isupper(ch)isupper((unsigned char)input[i])

  • 在将字节存储到i之前,不检查input[i]是否足够小,从而导致潜在的缓冲区溢出。请注意,没有必要将字符存储到数组中以解决您的问题。

  • 您应该将'_'插入数组转换为小写的字符。这是你的主要问题。

  • 您是希望将Main转换为_mainmain还是将Main转换为规范问题。

这是一个更简单的版本:

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

int main(void) {
    int c;

    while ((c = getchar()) != EOF) {
        if (isupper(c)) {
            putchar('_');
            putchar(tolower(c));
        } else {
            putchar(c);
        }
    }
    return 0;
}

答案 4 :(得分:0)

要在显示的表单中输出输入的字符,则无需使用数组。该程序可以采用以下方式

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

int main( void )
{
    int c;

    while ((c = getchar()) != EOF && c != '\n')
    {
        if (isupper(c))
        {
            putchar('_');
            c = tolower(c);
        }
        putchar(c);
    }

    putchar('\n');

    return 0;
}

如果你想使用一个字符数组,你应该为终止零保留一个元素,如果你想要数组包含一个字符串。

在这种情况下,程序看起来像

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

int main( void )
{
    char input[100];
    const size_t N = sizeof(input) / sizeof(*input);

    int c;
    size_t i = 0;

    while ( i + 1 < N && (c = getchar()) != EOF && c != '\n')
    {
        if (isupper(c))
        {
            input[i++] = '_';
            c = tolower(c);
        }
        if ( i + 1 != N ) input[i++] = c;
    }

    input[i] = '\0';

    puts(input);

    return 0;
}