用一个替换文件中的多个新行

时间:2015-06-26 05:38:04

标签: c file

此函数应该在文本文件中搜索新行字符。当找到换行符时,它会递增newLine计数器,当有超过2个连续的空行新行时,它会将所有空白行挤压成一个空白行。

在我的代码中,如果有2个新行,它会想要摆脱它们并将它们挤压成一个,为了测试目的,我还要打印它&#34; new line&#34;当它达到newLine < 2条件时。现在它为每一个新行打印新行,无论是否为空白,并且没有消除额外的新行。我究竟做错了什么?

编辑:这是我的完整代码 http://pastebin.com/bsD3b38a

所以基本上程序假设将两个文件连接在一起,而不是对它们执行各种操作,就像我试图做的那样,摆脱多个连续的空白新行。 所以为了在cygwin中执行它我做 ./a -s file1 file2 它假设将file1和file2连接到一个名为contents.txt的文件中,然后除掉连续的新行并将它们显示在我的cygwin终端(stdout)上。 (-s调用函数去掉连续的行)。传入的第三个和第四个参数(file1和file2)是两个文件,它们假设它们连接成一个名为contents.txt的文件,squeeze_lines函数比读取contents.txt文件并假设挤压新行。您可以在下面看到我放在file1.txt中的内容的示例。 file2.txt只有一堆单词后跟空的新行。

int newLine = 1;
int c; 

if ((fileContents = fopen("fileContents.txt", "r")) == 0) 
{
    perror("fopen");
    return 1; 
}

while ((c = fgetc(fileContents)) != EOF)
{   
    if (c == '\n')
    {
        newLine++;
        if (newLine < 2) 
        {
            printf("new line");
            putchar(c); 
        }
    }
    else 
    {
        putchar(c); 
        newLine = 0;
    }
}

程序在带有这些内容的.txt文件中读取的文件。它假设读取文件,摆脱前导和连续的新行,并将新的格式化内容输出到我的cywgin终端上的stdout。

/* hello world program */


#include <stdio.h>

    tab
            2tabs

5 个答案:

答案 0 :(得分:3)

诊断

逻辑看起来正确如果你有Unix行结尾。如果你有Windows CRLF行结尾但是在Unix上处理文件,你在每个LF之前都有一个CR,并且CR将newLine重置为零,所以你得到每个换行符的消息。

这可以解释你所看到的。

这也可以解释为什么其他人都在说你的逻辑是正确的(只要这些行以LF而不是CRLF结束),但你会看到意想不到的结果。

如何解决?

公平的问题。一个主要选项是使用dos2unix或等效机制将DOS文件转换为Unix文件。 SO上有很多关于这个问题的问题。

如果您根本不需要CR({C '\r')字符,则只需删除(不打印,而不是归零newLine)。

如果您需要保留CRLF行结尾,则需要更加小心。你必须记录你有一个CR,然后检查你得到一个LF,然后打印该对,然后检查你是否得到更多的CRLF序列并抑制它们等。

工作代码 - dupnl.c

该程序仅从标准输入读取;这比以前更灵活 只读取固定文件名。学会避免编写代码 仅适用于一个文件名;它会为你节省大量的重新编译 随着时间的推移。 Th代码仅处理带有换行符("\n")的Unix样式文件 在末尾;它还处理带有CRLF("\r\n")结尾的DOS文件;和 它还使用CR处理(旧式)Mac(Mac OS 9及更早版本)文件 ("\r")行结尾。事实上,它涉及任意交错 不同的行结束样式。如果你想强制执行一个 模式,你必须做一些工作来决定哪种模式,然后使用 该代码的适当子集。

#include <stdio.h>

int main(void)
{
    FILE *fp = stdin;       // Instead of fopen()
    int newLine = 1;
    int c; 

    while ((c = fgetc(fp)) != EOF)
    {   
        if (c == '\n')
        {
            /* Unix NL line ending */
            if (newLine++ == 0)
                putchar(c); 
        }
        else if (c == '\r')
        {
            int c1 = fgetc(fp);
            if (c1 == '\n')
            {
                /* DOS CRLF line ending */
                if (newLine++ == 0)
                {
                    putchar(c);
                    putchar(c1);
                }
            }
            else
            {
                /* MAC CR line ending */
                if (newLine++ == 0)
                    putchar(c);
                if (c1 != EOF && c1 != '\r')
                    ungetc(c1, stdin);
            }
        }
        else
        {
            putchar(c); 
            newLine = 0;
        }
    }

    return 0;
}

示例运行 - 输入和输出

$ cat test.unx


data long enough to be seen 1 - Unix

data long enough to be seen 2 - Unix
data long enough to be seen 3 - Unix
data long enough to be seen 4 - Unix



data long enough to be seen 5 - Unix


$ sed 's/Unix/DOS/g' test.unx | ule -d > test.dos
$ cat test.dos


data long enough to be seen 1 - DOS

data long enough to be seen 2 - DOS
data long enough to be seen 3 - DOS
data long enough to be seen 4 - DOS



data long enough to be seen 5 - DOS


$ sed 's/Unix/Mac/g' test.unx | ule -m > test.mac
$ cat test.mac
$ ta long enough to be seen 5 - Mac
$ odx test.mac
0x0000: 0D 0D 64 61 74 61 20 6C 6F 6E 67 20 65 6E 6F 75   ..data long enou
0x0010: 67 68 20 74 6F 20 62 65 20 73 65 65 6E 20 31 20   gh to be seen 1 
0x0020: 2D 20 4D 61 63 0D 0D 64 61 74 61 20 6C 6F 6E 67   - Mac..data long
0x0030: 20 65 6E 6F 75 67 68 20 74 6F 20 62 65 20 73 65    enough to be se
0x0040: 65 6E 20 32 20 2D 20 4D 61 63 0D 64 61 74 61 20   en 2 - Mac.data 
0x0050: 6C 6F 6E 67 20 65 6E 6F 75 67 68 20 74 6F 20 62   long enough to b
0x0060: 65 20 73 65 65 6E 20 33 20 2D 20 4D 61 63 0D 64   e seen 3 - Mac.d
0x0070: 61 74 61 20 6C 6F 6E 67 20 65 6E 6F 75 67 68 20   ata long enough 
0x0080: 74 6F 20 62 65 20 73 65 65 6E 20 34 20 2D 20 4D   to be seen 4 - M
0x0090: 61 63 0D 0D 0D 0D 64 61 74 61 20 6C 6F 6E 67 20   ac....data long 
0x00A0: 65 6E 6F 75 67 68 20 74 6F 20 62 65 20 73 65 65   enough to be see
0x00B0: 6E 20 35 20 2D 20 4D 61 63 0D 0D 0D               n 5 - Mac...
0x00BC:
$ dupnl < test.unx
data long enough to be seen 1 - Unix
data long enough to be seen 2 - Unix
data long enough to be seen 3 - Unix
data long enough to be seen 4 - Unix
data long enough to be seen 5 - Unix
$ dupnl < test.dos
data long enough to be seen 1 - DOS
data long enough to be seen 2 - DOS
data long enough to be seen 3 - DOS
data long enough to be seen 4 - DOS
data long enough to be seen 5 - DOS
$ dupnl < test.mac
$ ta long enough to be seen 5 - Mac
$ dupnl < test.mac | odx
0x0000: 64 61 74 61 20 6C 6F 6E 67 20 65 6E 6F 75 67 68   data long enough
0x0010: 20 74 6F 20 62 65 20 73 65 65 6E 20 31 20 2D 20    to be seen 1 - 
0x0020: 4D 61 63 0D 64 61 74 61 20 6C 6F 6E 67 20 65 6E   Mac.data long en
0x0030: 6F 75 67 68 20 74 6F 20 62 65 20 73 65 65 6E 20   ough to be seen 
0x0040: 32 20 2D 20 4D 61 63 0D 64 61 74 61 20 6C 6F 6E   2 - Mac.data lon
0x0050: 67 20 65 6E 6F 75 67 68 20 74 6F 20 62 65 20 73   g enough to be s
0x0060: 65 65 6E 20 33 20 2D 20 4D 61 63 0D 64 61 74 61   een 3 - Mac.data
0x0070: 20 6C 6F 6E 67 20 65 6E 6F 75 67 68 20 74 6F 20    long enough to 
0x0080: 62 65 20 73 65 65 6E 20 34 20 2D 20 4D 61 63 0D   be seen 4 - Mac.
0x0090: 64 61 74 61 20 6C 6F 6E 67 20 65 6E 6F 75 67 68   data long enough
0x00A0: 20 74 6F 20 62 65 20 73 65 65 6E 20 35 20 2D 20    to be seen 5 - 
0x00B0: 4D 61 63 0D                                       Mac.
0x00B4:
$

$ ta开头的行是提示覆盖前一个输出的位置(“足够长到可见”部分是因为我的提示通常比$更长)。

odx是十六进制转储程序。 ule用于“统一行结尾”并分析或转换数据,使其具有统一的行结尾。

Usage: ule [-cdhmnsuzV] [file ...]
  -c  Check line endings (default)
  -d  Convert to DOS (CRLF) line endings
  -h  Print this help and exit
  -m  Convert to MAC (CR) line endings
  -n  Ensure line ending at end of file
  -s  Write output to standard output (default)
  -u  Convert to Unix (LF) line endings
  -z  Check for zero (null) bytes
  -V  Print version information and exit

答案 1 :(得分:2)

示例代码解决的是:

1)将连续的几个'\ n'挤压到一个'\ n'

2)如果有的话,在开头摆脱前导'\ n'。

  input:   '\n\n\naa\nbb\n\ncc' 
  output:   aa'\n'    
            bb'\n' //notice, there is no blank line here
            cc

如果是目的,那么你的代码逻辑就是正确的。

  • 通过定义newLine = 1,它将摆脱任何领先的'\ n' 输入txt。

  • 当处理完毕后仍有'\ n'时,它会输出一个new line来提示。

回到问题本身,如果实际目的是将连续的空白行挤压到一个空行(需要两个连续'\ n',一个用于终止上一行,一行为空行。)

1)让我们首先确认输入和预期输出,

输入文字:

aaa'\n' //1st line, there is a '\n' append to 'aaa'  
'\n'    //2nd line, blank line
bbb'\n' //3rd line, there is a '\n' append to 'bbb'
'\n'    //4th line, blank line
'\n'    //5th line, blank line
'\n'    //6th line, blank line
ccc     //7th line,

预期输出文字:

aaa'\n' //1st line, there is a '\n' append to 'aaa'  
'\n'    //2nd line, blank line
bbb'\n' //3rd line, there is a '\n' append to 'bbb'
'\n'    //4th line, blank line
ccc     //5th line,

2)如果它是上面的确切程序目标,那么

if (c == '\n')
{
    newLine++;
    if (newLine < 3) // here should be 3 to print '\n' twice,
                     // one for 'aaa\n', one for blank line 
    {
        //printf("new line");
        putchar(c); 
    }
}

3)如果你必须在Cygwin下处理Windows格式文件(结尾为\r\n),那么你可以这样做

while ((c = fgetc(fileContents)) != EOF)
{   
    if ( c == '\r') continue;// add this line to discard possible '\r'
    if (c == '\n')
    {
        newLine++;
        if (newLine < 3) //here should be 3 to print '\n' twice
        {
            printf("new line");
            putchar(c); 
        }
    }
    else 
    {
        putchar(c); 
        newLine = 0;
    }
}

答案 2 :(得分:1)

[EDITED] 最小的变化是:

if ( newLine <= 2)

原谅我,忘了以前的代码。

一个稍微简单的替代方案:

int c;
int duplicates=0;
while ((c = fgetc(fileContents)) != EOF)
{
    if (c == '\n') {
        if (duplicates > 1) continue;
        duplicates++;
    }
    else {
        duplicates=0;
    }
    putchar(c);
}

答案 3 :(得分:0)

干跑代码: 如果文件以换行符开头且newLine1

第一次迭代:

if (c == '\n') //Will be evaluated as true for a new-line character. 
{
    newLine++; //newLine becomes 2 before next if condition is evaluated.
    if (newLine < 2) //False, since newLine is not less than 2, but equal.
    {
        printf("new line");
        putchar(c); 
    }
}
else //Not entered
{
    putchar(c); 
    newLine = 0;
}

在第二次迭代中:(假设它是一个连续的换行符char)

if (c == '\n') //Will be evaluated as true for a new-line character.
{
    newLine++; //newLine becomes 3 before next if condition is evaluated.
    if (newLine < 2) //False, since newLine is greater than 2.
    {
        printf("new line");
        putchar(c); 
    }
}
else //Not entered
{
    putchar(c); 
    newLine = 0;
}

所以,

  • newLine初始化为0

答案 4 :(得分:0)

if newline > 2     

如果你想摆脱第二行,那应该大于或等于。 你还有一行换行,然后递增到2,然后重置为零。相反,我建议用类似

的布尔值替换计数
boolean firstNewlineFound = false

然后每当你找到换行符时将其设置为true;只要是真的,删除onenewline并将其设置为false。