从C中重定向的stdin输入验证

时间:2012-04-13 00:46:22

标签: c validation stdin

我正在尝试用C语言编写一个程序来检测CSV格式,例如。 decimalcommadecimal。并给出关于文件是否是所需格式的输出。我尝试过使用stdin的各种输入并使用isdigit等但没有成功。我是一个大型菜鸟,之前几乎没有做过任何C编程,我试图使用regexc,但无法弄清楚使用它的语法。

#include <ctype.h>
#include <stdio.h>
const char EOL = '\n';

int cbreak(void);
int check_dig(void);
int value =1;
char c;

int main()
{

    while((scanf("%c" ,&c)) !=EOF&& value !=0)
    check_dig();

    printf("\n%d\n",value);
}

int check_dig()
{
    if (c == EOL)
        scanf("%c", &c);
    if (c == isdigit)
        scanf("%c", &c);
    else if (c == ',')
        scanf("%c", &c);
    else value = 0;
}

谢谢大家我现在已经到了这个阶段,但是如果要完成,我需要打印1或0取决于验证,我想按照建议使用返回值。

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

int check_digit(int);
int check_comma(int);
int skip_char(int);
int main()
{
    int c;

    while ((c = getchar()) !=EOF)
        if (check_digit(c))
            skip_char(c);
        else if (check_comma(c))
            skip_char(c);
        else return 0;
}

int check_digit(int c)
{   
    if (isdigit(c))
        return 1;
    else return 0;
}    

int check_comma(int c)
{
    if (c == ',')
        return 1;
    else return 0;
}

int skip_char(int c)
{
    c = getchar(); // will this skip 2 chars as i have a while loop that has c=getchar()??
    return c;
}

2 个答案:

答案 0 :(得分:0)

首先,我建议不要使用那么庞大的全局变量列表。使用函数中的参数并从函数返回值。

第二个isdigit不起作用。它需要一个参数并返回true或false。 isdigit

此外,我会使用getchar而不是scanf。

您的int check_dig()功能有点奇怪。你一直在阅读函数内的字符。

我可能会做类似的事情:

int valid_csv(char c)
{
    if (isdigit(c))
        return 1;
    /* etc. other checks */
    if all fails
    return 0;
}

int main(void)
{
    int c;

    /* read chars into c and call fun by something like */
    valid_svc(c);

    return 0;
}

编辑:根据经验。一个函数应该只做一件事,而且只做一件事,做得好。函数的名称应该反映它的作用。


Edit.2:

您不需要“跳过字符”。在你的新代码中,它的方式就是你跳过其他所有角色。

即:

档案:12,33,66,14

在您的代码中,您将获得

  • c = getchar =&gt; c == 1
  • c是数字
    • getchar =&gt;你读2(并且从不验证它)
  • c = getchar =&gt; c ==,
  • c是逗号
    • getchar =&gt;你读3(并且从不验证它)
  • ...

此外;我知道我写过“一个函数应该做一件事” - 但不是那个文字。即你的新check_digit是多余的。直接使用isdigit。如果您的csv中有浮动,则必须扩展或使用不同的方法。

以举例说明;更容易再写在这里:)

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

int valid_csv_chr(int);
int valid_csv(); /* guess naming could be better. */

int main(void)
{
    if (valid_csv())
        puts("1");
    else
        puts("0");

    return 0; /* Main should return 0 if there was no "crash" scenario etc.
     * You could also return i.e. 1 if the file is not validated as csv. 
     * Do not think of 1 and 0 as boolean true / false here. */
}

int valid_csv()
{
    int c;

    while((c = getchar()) !=EOF) {
        if (!valid_csv_chr(c)) {
            return 0;
        }
    }

    return 1;
}

int valid_csv_chr(int c)
{
    if (isdigit(c))
        return 1;
    if (c == ',')
        return 1;
    if (c == '\n')
        return 1;
        /* add checks for space etc. */
    return 0;
}

Edit.3:

代码结构是人们必须学习的东西,就像语言本身一样。它是通过实践和写作来学习的。那个人意识到必须不时地重新编写代码结构 - 但是在编写之前思考的越多,首先要做一个简单的结构并扩展它,等等。这是更容易避免的。

总之;练习,练习,练习。并始终牢记这些主题。

即使它“看起来”简单,但事实并非如此。我认为通常书籍,教程,课程等都很少关注这个主题。这完全取决于forif,功能等等,而且对于如何以 良好的 方式将它们拼接在一起几乎没有。< / p>

分割代码有几个好处。

  • 它使它更具可读性。
  • 使维护更容易。
  • 错误和错误通常可以通过修复一个小函数而不是一个巨大函数来修复。
    • 在某些情况下,我看到了数千行代码,其中一行有一些怪物功能。通过调整来修复它几乎是不可能的,完全重写只是一种选择。
  • 优化执行一项任务的功能更容易,并且不会很大。
  • 使用较小的功能时,更容易扩展以涵盖更多场景。
    • 比如你的程序。您可以将其更改为“验证数据文件”,包括csv,制表符分隔,对齐等。

最后一点实际上是我写作时经常想到的一种方式; “我应该如何最好地实现这个代码,以便将来,如果我想扩展它以涵盖更多场景,那么可以轻松完成。”

我自己使用this作为 基础 在用C语言写作时结合我在K&amp; K中学到的东西R的ANSI C book ++。例如,请参阅有关functions的内容。

也;严格的编码风格使其更容易阅读和维护。我在很大程度上使用了上面文档中描述的内容。这不是 law ,但是有意识地使编码生活变得更加简单。

答案 1 :(得分:0)

我不建议使用regexc来解决这个问题,特别是如果你是C的新手。你应该能够使用一些基本的标准库功能解决它。你似乎在正确的轨道上。您正在阅读字符并确定它们适合哪个类。由于您知道有效输入仅包含数字和逗号字符,因此如果遇到任何不属于这两种情况的内容,您可以立即终止该程序。以下是一些可能有用的提示。

如果您一次只读一个角色,getchar可能比scanf更容易使用。

此外,isdigit是一个功能。您想说if (c == isdigit)

,而不是说if (isdigit(c))

您的函数check_dig被定义为返回int,但函数中没有return语句。需要修改函数以返回值,main需要对此值执行某些操作。一般的经验法则是函数在成功完成时返回零,或者在错误时返回非零值。在你的情况下,“成功”可能意味着“角色有效”,“错误”可能意味着“角色无效”。进行此更改应该可以消除全局变量value。如果您将输入作为参数传递给c,那么您也可以删除全局check_digc将成为main()内的局部变量。)

我建议您仅使用check_dig功能检查数字,并删除读取其他字符的部分。在调用check_dig之前,您应该决定是否跳过一个字符。这样,您就可以分离“读取”代码,“跳过”代码和“检查”代码。这使您的程序更易于阅读和调试。