简体   繁体   English

如何在C中检查stdin == stdout

[英]How to check if stdin == stdout in C

I am building a program that takes user input, manipulates it, and outputs the changes (if any). 我正在构建一个程序,它接受用户输入,对其进行操作并输出更改(如果有)。 The guidelines are: 准则是:

  1. Delete all digits 删除所有数字
  2. if > 2 newlines in a row, print only 2 如果连续> 2个换行符,则仅打印2
  3. change cases of letters 更改字母大小写
  4. print 2 spaces for each space 每个空间打印2个空间
  5. print all other characters normally 正常打印所有其他字符
  6. Return a 1 from main if the stdin and stdout are the same, a 0 if not. 如果stdin和stdout相同,则从main返回1;否则返回0。

I cannot use any data structure for this project, so I am using getchar() to read stdin char by char. 我不能为此项目使用任何数据结构,因此我正在使用getchar()逐字符读取stdin char。

Is there any way to compare stdin to stdout in C? 有什么方法可以在C中将stdin与stdout进行比较? I am new to the language and do not know how to even look into this. 我是该语言的新手,甚至不知道如何进行研究。 My code with all guidelines satisfied sans 6 is below: 下面是我的代码,所有准则均满足,条件不满足6:

#include <stdio.h>

int newline(int iochar);
void testChars(int iochar);
void upperCase(int iochar);
void lowerCase(int iochar);
void space(int iochar); 
void digit();


int main()
{
    int iochar = 0;
    iochar = getchar();

    testChars(iochar);

    return 0;
}

void testChars(int iochar)
{
    while(iochar != EOF) {
        if (iochar == 10)
            iochar = newline(iochar);

        else if(iochar == 32)
        space(iochar);

        else if (iochar > 64 && iochar < 91)
        upperCase(iochar);

        else if (iochar < 123 && iochar > 96)
        lowerCase(iochar);

        else if (iochar < 58 && iochar > 47)
        digit();

        else putchar(iochar);

        iochar = getchar();
    }
}

void space(int iochar)
{
    putchar(iochar);
    putchar(iochar);
}

int newline(int iochar)
{
    int count = 0;
    while (iochar == 10){
        if(count < 2)
            putchar(iochar);
        count++; 
        iochar = getchar();
    }
    return iochar;
}

void digit()
{
    return;
}

void upperCase(int iochar)
{
    iochar += 32;
    putchar(iochar);
}

void lowerCase(int iochar)
{
    iochar -=32;
    putchar(iochar);
}

While you can break your tests up into multiple functions, since the number of cases you are handling is limited, simply including the tests directly in a single "state" loop that keeps track of the number of newlines and whether there have been any modifications to the input is an equally readable way to go. 尽管可以将测试分解为多个功能,但是由于要处理的案例数量有限,因此只需将测试直接包含在单个“状态”循环中即可,该循环可跟踪换行符的数量以及是否对代码进行了任何修改输入是同样可读的方式。 (good catch @iBug on the XY-Problem). (在XY问题上很好的@iBug)。

There are a number of ways to approach a character classification problem, which is essentially what you have. 解决字符分类问题的方法有很多种,基本上就是您所拥有的。 (meaning you read a character, classify whether if fits some predefined test, and then take some action depending on how it is classified). (意味着您阅读了一个字符,对是否适合某个预定义的测试进行分类,然后根据其分类方式采取一些措施)。 One efficient way to handle it is with a loop that keeps track of the state of things (eg "How many newlines have been sequentially read?", or whether I'm inside a word, reading whitespace, etc..) by setting, or resetting or incrementing a few variables that track whatever condition (or state) you are interested in that is based on something other than the current character. 一种有效的处理方法是使用循环,通过设置状态来跟踪事物的状态(例如“已顺序读取了几行换行符?”,或者我是否在单词中,在阅读空格等)。或重置或增加一些变量,这些变量会根据当前字符以外的其他内容来跟踪您感兴趣的任何条件(或状态)。

You simply figure out what you need to follow (here, the number of sequential newlines, and whether you have modified the output in any way). 您只需弄清楚需要遵循的内容(这里是连续换行符的数量,以及是否已以任何方式修改了输出)。 Easy enough, just keep a count of the sequential newlines read in an integer like nl and keep an integer flag you set if you make any changes, call it modified or something logical. 如此简单,只需对连续换行符进行计数就可以像nl这样的整数进行读取,并保留设置的整数标志(如果进行任何更改,称其为modified或逻辑上的值)。 When you read anything other than a '\\n' reset your newline count, eg nl = 0; 当您读取除'\\n'以外的任何内容时,请重置换行符计数,例如nl = 0; .

Then it is just a matter of reading each character of input until you encounter EOF and conducting a number of tests to determine what character you read (either using if, else if, else or using a switch statement). 然后,只需读取输入的每个字符,直到遇到EOF然后进行大量测试以确定要读取的字符即可(使用if, else if, else或使用switch语句)。 Then for each different test, take the appropriate action. 然后针对每个不同的测试,采取适当的措施。

For example, you could satisfy your criteria with something simple like: 例如,您可以使用以下简单的方法满足您的条件:

#include <stdio.h>

int main (void) {

    int c, modified = 0, nl = 0;

    while ((c = getchar()) != EOF) {        /* loop over each char       */
        if (c == '\n') {                    /* am I a '\n'?              */
            if (nl < 2)                     /* have I ouput less than 2? */
                putchar ('\n');             /* output the newline        */
            else
                modified = 1;               /* set modified flag         */
            nl++;                           /* update the number seen    */
            continue;                       /* get next char             */
        }
        else if ('A' <= c && c <= 'Z') {    /* am I uppercase?           */
            putchar (c + 'a' - 'A');        /* convert to lowercase      */
            modified = 1;                   /* set modified flag         */
        }
        else if ('a' <= c && c <= 'z') {    /* am I lowercase?           */
            putchar (c + 'A' - 'a');        /* convert to uppercase      */
            modified = 1;                   /* set modified flag         */
        }
        else if (c < '0' || '9' < c) {      /* am I not a digit?         */
            if (c == ' ') {                 /* am I a space ?            */
                putchar (c);                /* output extra space        */
                modified = 1;               /* set modified flag         */
            }
            putchar (c);                    /* output unmodified char    */
        }
        nl = 0;                 /* reset newlines seen to zero */
    }

    return modified ? 0 : 1;    /* 0 - modified, 1 - stdout == stdin */
}

note: try and avoid using magic numbers in your code. 注意:请尝试避免在代码中使用幻数 If you need the ASCII value of 'A' , then use 'A' , not 65 . 如果需要ASCII值'A' ,则使用'A'而不是65 Reading thought code that has magic numbers scattered about (eg 65 , 32 , 10 is not nearly as informative as 'A' , ' ' and '\\n' ). 阅读有神奇数字散落思想代码(例如653210是几乎没有的翔实的'A'' ''\\n' )。

Note also, you can use the macros is ctype.h (eg isupper() , islower() , isdigit() , etc..) to easily test what the current character is in a very readable manner. 还要注意,您可以使用ctype.h宏(例如isupper()islower()isdigit()等)来以非常易读的方式轻松测试当前字符。 There is also learning value in doing it manually to gain an understanding of what those convenient functions in ctype.h are actually doing and practicing setting up your conditional tests properly. 手动执行该操作还具有学习价值,以了解ctype.h中那些便捷的功能实际上在做什么,并练习正确设置条件测试。

Example Input File 输入文件示例

Now just create a test case to exercise your character classifications and make sure you loop is working the way it should. 现在,只需创建一个测试用例即可对您的角色进行分类,并确保循环以应有的方式工作。 There is nothing special required. 没有什么特别的要求。 Rather than trying to construct a myriad of assert() statements, just create an input file that has a character that fits each case: 与其尝试构造无数的assert()语句,不如创建一个具有适合每种情况的字符的输入文件:

$ cat dat/stateloop.txt
This Is a Line followed by THREE-newlines


and with SEVEN single-spaced asterisk * * * * * * *
aND a lINE fOLLOWED bY five nEWLINES ('\N')




And A Few Numbers zERO-tO-nINE (123456789)
1
a b c d e f g - A B C D E F G
Done2Day

Example Use/Output 使用/输出示例

Then carefully check the output: 然后仔细检查输出:

$ ./bin/stateloop <dat/stateloop.txt
tHIS  iS  A  lINE  FOLLOWED  BY  three-NEWLINES

AND  WITH  seven  SINGLE-SPACED  ASTERISK  *  *  *  *  *  *  *
And  A  Line  Followed  By  FIVE  Newlines  ('\n')

aND  a  fEW  nUMBERS  Zero-To-Nine  ()

A  B  C  D  E  F  G  -  a  b  c  d  e  f  g
dONEdAY

Check Return Value 检查返回值

and validate the return is correct. 并验证return是否正确。

$ echo $?
0

Try A (no-change) Case 尝试一个(不变的)案例

Do the same thing for the non-modified case: 对未修改的情况执行相同的操作:

$ printf "~@##$@#$%%#*[]{};:^^&&*)\n" | ./bin/stateloop
~@###$%#*[]{};:^^&&*)

Check Appropriate Return 检查适当的退货

$ echo $?
1

As noted earlier, there are many ways to approach this type of problem. 如前所述,有许多方法可以解决此类问题。 Just find something that is logical, robust, readable and understandable. 只是找到一些逻辑上,健壮,可读和可理解的东西。 Good luck with your coding. 祝您编码顺利。

It seems you're facing an XY problem. 看来您正面临XY问题。

From your description I read that the actual thing you want to do is to check whether the output is identical to the input . 从您的描述中,我读到您要执行的实际操作是检查输出是否与输入相同 So the solution is simple: You just need to track if at least one character has been modified during the process, and if yes then you know the input and the output will be different. 因此解决方案很简单:您只需要跟踪在此过程中是否至少修改了一个字符,如果是,则您知道输入和输出将不同。

int modified = 0;

void testChars(int iochar){
    while(iochar != EOF){
        if (iochar == 10){
            iochar = newline(iochar);
        } else if(iochar == 32) {
            space(iochar);
            modified++;
        } else if (iochar > 64 && iochar < 91) {
            upperCase(iochar);
            modified++;
        } else if (iochar < 123 && iochar > 96) {
            lowerCase(iochar);
            modified++;
        } else if (iochar < 58 && iochar > 47) {
            digit();
            modified++;
        } else {
            putchar(iochar);
            // Nothing modified
        }

        iochar = getchar();
    }
}

int newline(int iochar){
    int count = 0;
    while (iochar == 10){
        if (count < 2) {
            putchar(iochar);
        } else {
            modified++;
        }
        count++; 
        iochar = getchar();
    }
    return iochar;
}

Then test if modified == 0 and you'll know it. 然后测试是否modified == 0 ,您会知道的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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