为什么Console.WriteLine()函数在字符串中会缺少一些字符?

22

我有一个字符串,声明如下:

 string text = "THIS IS LINE ONE "+(Char)(13)+" this is line 2";

然而,当我写下Console.WriteLine(text);时,

输出结果是:

this is line 2E
为什么会出现这种行为?还是因为我太傻了,错过了一些显而易见的东西吗?
为什么它不打印:
THIS IS LINE ONE [CR] //where the CR is a non printed character 
this is line 2

编辑

请注意:这 不是 一个“如何添加回车符”的问题。


2
所以...我们已经确定您在标准控制台上的输出存在问题,而且这种输出必须是这样才能使打印机正常工作,但是您还没有测试过它在打印机上的表现或工作方式您确定自己真的有问题吗? - Lasse V. Karlsen
2
再次强调,这就是标准输出的行为。如果你不喜欢输出结果,那就改变你写入的文本内容。如果你不能改变,因为你只是为了调试目的而这样做,并且文本必须按照打印机的要求来,那么请停止使用标准控制台进行测试,改用打印机进行测试。 - Lasse V. Karlsen
3
好的,让我详细说明一下。打印机和控制台可能会表现不同。唯一确定它们是否相同的方法是使用实际设备——打印机进行测试。这不是Console.WriteLine的问题,也不是实际字符的问题,而是标准控制台行为的“问题”。打印机可能会或可能不会表现出相同的行为,控制台的行为对此没有影响。 - Lasse V. Karlsen
5
你的程序只是把所有这些字符传递给标准控制台,并要求它显示它们,它在换行字符方面的行为就像那样。打印机可能会完全不同。事实上,旧的针式打印机使用一个字符仅向下移动一行并继续沿着X轴走,另一个字符用于移动到该行的起始位置,因此你需要两个来获得你想要的效果。只有通过实际测试才能弄清楚这一点。 - Lasse V. Karlsen
3
根据你提到的另一个问题,其中你提到了OKI Microline 5520.. 我刚刚找到了http://www.manuals365.com/swf/oki/552xugb2_tcm3-46086.html?page=74。这意味着你想要字符10而不是字符13。 - Peter M
显示剩余12条评论
7个回答

58

(char)13是回车符(将光标移至当前行的左边界)

THIS IS LINE ONE \r this is line 2"

被解释为:

打印 这是第一行
然后 *返回* 并打印 这是第二行
重叠部分是: E
所以你看到: 这是第二行E


这是正确的,当字符串长度相等时就没有问题,例如:string text = "THIS IS LINE ONE " + (Char)(13) + " THIS IS LINE TWO"; - globetrotter
2
你说没有问题是什么意思?问题是第一行有剩余字符,还是光标不会移动到第二行(这似乎是原帖作者所指的)? - Lasse V. Karlsen
1
@LasseV.Karlsen Alex K. 解释得很好。它返回到第1行的开头,并将第2行打印在第1行之上。由于第1行较长,因此存在开销,因此在行尾有额外的'E'字符。要换行,您可以使用(char)10 - globetrotter
1
是的,OP问如何使(char)13移到下一行。对于OP来说,问题从未涉及剩余字符,而是为什么它没有向下移动到第二行而是覆盖了上一行。所以是的,答案很好地解释了为什么输出看起来那样,但对于OP来说仍然存在问题。虽然我认为OP只能妥协,不能得到他想要的东西。 - Lasse V. Karlsen
@LasseV.Karlsen 我明白你的意思,但(char)13不应该换到下一行。这是CR,应该是CRLF - globetrotter
所有这些都取决于OP说他的打印机是这样的事实。事实证明,它并不是这样的,所以我怀疑整个文本页面都是无用的。 - Lasse V. Karlsen

20

这是控制台上标准输出的行为。

  • "\n" ((Char)10) 将把光标移动到下一行的开头
  • "\r" ((Char)13) 将把光标移动到当前行的开头

因此,结果是第一行被第二行覆盖,并留下第二行不能覆盖的额外字符。

既然您已经澄清了字符串/字符必须像这样才能实现所需的行为,将该文本最终发送到点阵打印机时,那么您需要使用打印机进行测试。

上述行为仅局限于标准控制台。如果将相同的字符输出到“标准输出”,但已将其重定向到打印机,则打印机处理这些字符的定义很重要,并且这可能与标准控制台不同。

因此,您在标准控制台上看到的行为只是标准控制台的行为。您需要实际测试打印机以查看其表现如何。


5
如果您想要这种行为:
THIS IS LINE ONE [CR] //where the CR is a non printed character 
this is line 2

你需要这段代码:
        char a = (char)10;
        string text = "THIS IS LINE ONE" + a + "this is line 2"

        Console.WriteLine(text);

回车((Char)13)是一种控制字符或机制,用于将设备的位置重置为文本行的开头,因此您会经历这种行为。就像我说的,您需要使用(char)13来解决您的问题。


这实际上是“正确”的,但我需要将它转换为char(13)以适应打印机(因为打印机期望看到的就是这样)。 - jbutler483
6
那你可以创建自己的WriteLine方法,将13替换为10...? - Sebastian Negraszus

4
“回车符”有时也称为“插入卡带”或简称为CR或Return,是一种控制字符或机制,用于将设备的位置重置到文本行的开头。”(来源)
“CR”永远不会更改行,实际上它返回到“THIS IS LINE ONE”的开头,并在其上打印“this is line 2”,因此您可以看到句子末尾额外的“E”,因为第一行比第二行长一个字符。如果从两个字符串中删除两个空格(第一个字符串的最后一个字符和第二个字符串的第一个字符),则可以更清楚地理解这一点,输出结果变成了“this is line 2NE”。
来自同一来源:
“它命令打印机或其他输出系统(例如显示器)将光标位置移动到同一行的第一个位置。”
你需要的不是 CR,而是 CRLF(换行符)的组合:CRLF

2

(Char)13 是回车符,而 (Char)10 是换行符。正如其他人所说,这意味着 (Char)13 会返回到当前行的开头,因此当您写下较短的第二行时,它将覆盖字符串的第一部分 - 因此剩余的 "E"。

如果您尝试使用较短的第二个字符串,就可以看到这种情况发生:

string text = "THIS IS LINE ONE " + (Char)13 +"test";
Console.WriteLine(text);

输出结果如下:

"test IS LINE ONE"

因此,要解决您的问题,正确的代码将是:
string text = "THIS IS LINE ONE " + (Char)10 +"test";
Console.WriteLine(text);

输出结果如下:

THIS IS LINE ONE
this is line 2

编辑:

原本,由于您说您的打印机需要(Char)13,我建议尝试 (Char)10 + (Char)13(或反之亦然)以达到类似的效果。然而,得益于Peter M非常有帮助的评论,看来您正在使用的打印机品牌确实只需要 (Char)10 - 根据手册(Char)10会产生回车和换行符,这正是您需要的。


2
点阵打印机命令可能是一门“黑魔法”,并且非常依赖于制造商,因此在您知道确切的品牌和型号,并且已经在您的桌子上测试了代码并且只有当您要部署该精确打印机时,才能宣称为打印机提供任何解决方案。 :-) - Peter M
这是一个公正的观点 - 我编辑了我的回答,建议将其作为可尝试的内容,而不是完整的解决方案。如果这使得这个回答在原作者的情况下变得无关紧要,虽然它确实解决了我电脑上的问题,我可以将其删除。 :-) - Luna
3
楼主透露了另一个问题,其中涉及到打印机。我谷歌搜索了相关命令并找到了http://www.manuals365.com/swf/oki/552xugb2_tcm3-46086.html?page=74,可以在回答中自由引用该链接。 - Peter M
从我阅读的参考资料来看,他确实想要Char 10! - Peter M
1
@PeterM:虽然点阵命令因制造商而异,但至少在历史上,我发现它们相对简单。我预计能够进行重印的打印机通常会将“CR”视为一个命令,从同一行的开头开始覆盖后面的内容;只有使用相同电机驱动车轴和进纸的设备才无法管理该命令。 - supercat

2

输出结果并不是看起来的那样。你的终端程序因为将回车符解释成了文本布局命令(即回到行首),从而隐藏了stdout中写入的一些字符的字节。通过十六进制转储,可以确认输出结果是正确的,因为它显示了输出结果的确切字节。

using System;
public class Hello1 {
  public static void Main()  {
     string text = "THIS IS LINE ONE "+(Char)(13)+" this is line 2";
     System.Console.WriteLine(text);
   }   
}

编译和运行:

$ gmcs a.cs
$ ./a.exe
 this is line 2E
$ ./a.exe | hexdump -C
00000000  54 48 49 53 20 49 53 20  4c 49 4e 45 20 4f 4e 45  |THIS IS LINE ONE|
00000010  20 0d 20 74 68 69 73 20  69 73 20 6c 69 6e 65 20  | . this is line |
00000020  32 0a                                             |2.|
00000022

-2
使用 string.Concat() 来连接字符串

string text = String.Concat(...)

并尝试打印这个


1
尽管如此,这并不改变打印输出是错误的事实。 - Arturo Torres Sánchez
在C#中,+符号会调用String.Concat方法(除非像这种情况一样可以在编译时执行连接操作)。 - Ben Voigt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接