【问题标题】:Multiple blank lines are not squeezed in one blank line(C) using I/O redirection使用 I/O 重定向不会将多个空行压缩在一个空行中 (C)
【发布时间】:2017-06-07 10:05:09
【问题描述】:

我被要求将输入中的两个或多个连续空白行压缩为输出中的一个空白行。所以我必须使用 Cygwin 来做 I/O 或测试它。 示例:./Lab test2.txt

我的代码是:

   int main(void){

    format();
    printf("\n");
    return 0;
}


void format(){
    int c;
    size_t nlines = 1;
    size_t nspace = 0;
    int spaceCheck = ' '; 

    while (( c= getchar()) != EOF ){

        /*TABS*/
        if(c == '\t'){
            c = ' ';
        }
        /*SPACES*/
        if (c ==' '){/*changed from isspace(c) to c==' ' because isspace is true for spaces/tabs/newlines*/
           /* while (isspace(c = getchar())); it counts while there is space we will put one space only */
            if(nspace > 0){
                continue;
            }
            else{
                putchar(c);
                nspace++;
                nlines = 0;
            }

        }


        /*NEW LINE*/
        else if(c == '\n'){
            if(nlines >0){
                continue;
            }
            else{
                putchar(c);
                nlines++;
                nspace = 0;
            }

        }   


        else{
            putchar(c);
            nspace = 0;
            nlines = 0;

        }       







    }

}

但是我的 test2.txt 没有我想要的结果。我的逻辑/代码有问题吗?

【问题讨论】:

  • 输入else { nlines = 0; } 来重置计数器。
  • 这个问题的逻辑相同:stackoverflow.com/questions/44402182/…
  • c = '\n'; 如果c == '\n' 已经适用,那绝对是徒劳的......
  • @Shiva 不,它仍然不起作用。但感谢您的回答
  • @Aconcagua 我只想将它设置为一个新的空白行。是否已经有空行也没关系。

标签: c


【解决方案1】:

您提供的代码太少,有趣的部分是围绕您发布的代码的循环...

你实际上要做的是跳过输出:

FILE* file = ...;
char c, prev = 0;
while((c = fgets(file)) != EOF)
{
    if(c != '\n' || prev != '\n')
        putchar(c);
    prev = c;
}

如果我们有一个空行跟随另一个空行,那么我们会遇到两个后续换行符,所以cprev都等于'\n',这是我们不想输出c的情况(随后的换行符)——相反的情况是两者都不等于'\n',正如你在上面看到的——并且只有这样你想要输出你的角色......

旁注:prev = 0 - 好吧,我需要将它初始化为不同于换行符的任何内容,也可以是 's' - 当然,除非你也想跳过最初的空行,然后你必须用'\n'初始化它...

Edit,指的是您修改过的代码:Edit2 (在再次更改时删除了对代码的引用)

由于您修改后的代码表明您不仅要压缩空白行,还希望压缩空格,因此您首先必须考虑您有两类空白,一方面是换行符,另一方面是任何其他。所以你必须适当区分。

我现在建议使用某种状态机:

#define OTH  0
#define WS   1
#define NL1  2
#define NL2  3

int state = OTH;

while (( c= getchar()) != EOF )
{
    // first, the new lines:
    if(c == '\n')
    {
        if(state != NL2)
        {
            putchar('\n');
            state = state == NL1 ? NL2 : NL1;
        }
    }
    // then, any other whitespace
    else if(isspace(c))
    {
        if(state != WS)
        {
            putchar(' ');
            state = WS;
        }
    }
    // finally, all remaining characters
    else
    {
        putchar(c);
        state = OTH;
    }
}

第一次区分发生在当前字符自己的类(换行符、空格或其他)上,第二次区分根据定义当前状态的前一个字符的类。输出总是针对任何非空白字符,或者如果只有两个后续空白字符,如果它们属于不同的类(换行符有点具体,我需要两种状态,因为我们想留下一个空白行,这意味着我们需要随后的两个换行符...)。

注意:只有空格的行在上述算法中不能作为空行应用,因此它们不会被消除(但会减少为包含一个空格的行)。从您发布的代码中,我认为这是有意...

为了完整起见:这是一个完全删除前导和尾随空格并将仅包含空格的行视为空行的变体:

if(c == '\n')
{
    if(state != NL2)
    {
        putchar('\n');
        state = state == NL1 ? NL2 : NL1;
    }
}
else if(isspace(c))
{
    if(state == OTH)
        state = WS;
}
else
{
    if(state == WS)
    {
        putchar('');
    }
    putchar(c);
    state = OTH;
}

秘密:如果之前有非ws字符,则只进入空格状态,但在遇到下一个非空格之前不打印空格字符。

来到换行符 - 好吧,如果有 一个普通字符,我们要么处于 OTH 状态,要么处于 WS 状态,但没有两个 NL 状态。如果该行只有空格,则状态不会被修改,因此我们保持在相应的NL状态(1或2)并相应地跳过该行...

【讨论】:

  • 您好!我编辑并添加了我的整个程序。请看一看。
  • 此代码不起作用。请再看看我的代码好吗?
【解决方案2】:

剖析这个:

if(c == '\n') {
        nlines++;

nlines 是否曾被重置为零?

        if(nlines > 1){
            c = '\n';

第三个\n 会发生什么? nlines > 1 会是真的吗?想想吧!

        }
}
putchar(c);

我不明白:无论如何,你无条件地输出你的角色,违背了检查它是否是换行符的整个目的。

c 是换行符并且不输出任何内容时,正确的解决方案会设置一个标志。然后,当c 不是换行符(else 分支)时,如果设置了标志并重置标志,则输出一个换行符。我现在把代码写给你:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-25
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    相关资源
    最近更新 更多