此函数应该在文本文件中搜索新行字符。当找到换行符时,它会递增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
答案 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)
干跑代码:
如果文件以换行符开头且newLine
为1
:
第一次迭代:
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。