将空白行挤压到C中的一个空行

时间:2017-06-09 04:04:05

标签: c

您好,请参考相同的问题,但代码不同。

Replacing multiple new lines in a file with just one

int main(void){

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

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

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

        /*TABS*/
        if(c == '\t'){
            c = ' ';
        }
        /*SPACES*/
        if (c ==' '){
            if(nspace > 0){
                continue;
            }
            else{
                putchar(c);
                nspace++;
                nlines = 0;
            }
        }

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

我想将多个空白行挤入一个空白行,但它似乎无法正常工作,在stdout上的Cygwin终端上,最后一行给了我额外的空白行,尽管输入没有空白最后一行。

例如
INPUT

Hello   Hi\n
\n
\n
Hey\t\tHola\n

期望的输出

Hello Hi\n
\n
Hey Hola\n

实际输出

Hello Hi\n
Hey Hola\n

请解释一下!

2 个答案:

答案 0 :(得分:1)

您正在递增nlines两次:

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

你只想做一次。我建议只需递增计数器直到它达到2然后再不再增加它。这只是一个小小的变化:

    if(nlines >= 2){
        continue;
    }

答案 1 :(得分:1)

这是您的代码的变体。我删除了format()函数(这对我来说很不寻常,因为SO上的大部分程序都没有使用足够的函数)直接将它合并到main()中。该代码现在更加对称地处理空格和换行符,修复了paddy answer中确定的双增量问题。如果最后还没有换行,它也只会在最后打印出换行符。这样可以标准化不以换行符结尾的文件。 nlines = 1;的初始化处理文件开头的多个换行符 - 这已经很好了。

#include <stdio.h>

int main(void)
{
    int c;
    size_t nlines = 1;
    size_t nspace = 0;

    while ((c = getchar()) != EOF)
    {
        if (c == '\t')
            c = ' ';
        if (c == ' ')
        {
            if (nspace < 1)
            {
                putchar(c);
                nspace++;
                nlines = 0;
            }
        }
        else if (c == '\n')
        {
            if (nlines < 2)
            {
                putchar(c);
                nlines++;
                nspace = 0;
            }
        }
        else
        {
            putchar(c);
            nspace = 0;
            nlines = 0;
        }
    }
    if (nlines == 0)
        putchar('\n');
    return 0;
}

我的测试使用了一些特定于Bash的表示法。我的计划是sb73: 最后一个测试输入不包括最终换行符。输出使用⌴表示输出中的换行符:

$ echo $'Hello   Hi\n\n\nHey\t\tHola\n' | sb73
Hello Hi⌴
⌴
Hey Hola
⌴
$

$ echo $'\n\nHello   Hi\n\n\n    Hey\t\tHola\n' | sb73
⌴
Hello Hi⌴
⌴
 Hey Hola⌴
⌴
$

$ printf '%s' $'\n\nHello   Hi\n\n\n    Hey\t\tHola' | sb73
⌴
Hello Hi⌴
⌴
 Hey Hola⌴
$

处理CRLF行结尾

注释表明上面的代码不能在Cygwin终端上运行,并且可能的原因是被修改的数据具有CRLF行结尾。有很多方法可以解决这个问题。一种是找到一种强制标准输入进入文本模式的方法。在文本模式下,CRLF行结尾应该映射到输入上的Unix样式'\n'(仅限NL或LF)结尾,并且Unix样式的行结尾应该映射到输出上的CRLF行结尾。

或者,可以简单地忽略CR字符:

--- sb73.c  2017-06-08 22:04:28.000000000 -0700
+++ sb47.c  2017-06-08 22:40:24.000000000 -0700
@@ -19,6 +19,8 @@
                 nlines = 0;
             }
         }
+        else if (c == '\r')
+            continue;    // Windows?
         else if (c == '\n')
         {
             if (nlines < 2)

这是一个统一的差异&#39;在代码中显示两行。或者可以处理CR后面没有LF作为常规字符,但处理CR后跟LF作为换行组合:

--- sb73.c  2017-06-08 22:04:28.000000000 -0700
+++ sb59.c  2017-06-08 22:42:43.000000000 -0700
@@ -19,6 +19,17 @@
                 nlines = 0;
             }
         }
+        else if (c == '\r')
+        {
+            if ((c = getchar()) == '\n')
+            {
+               ungetc(c, stdin);
+               continue;
+            }
+            putchar('\r');
+            nspace = 0;
+            nlines = 0;
+        }
         else if (c == '\n')
         {
             if (nlines < 2)

可能有办法编写处理CR的状态机,但这会更复杂。

我有一个utod程序,可以将Unix风格的行结尾转换成Windows风格;我在管道中使用它来测试代码的新变种。