【问题标题】:How to print control characters in Console Window如何在控制台窗口中打印控制字符
【发布时间】:2012-09-07 18:27:20
【问题描述】:

我有按 ASCII (09) 或 Unicode 分配的制表符

char ch = '\x09';
(or)
char ch = '\u0009';

如何在控制台窗口中打印'\t'

以下都不起作用。(也许它打印一个选项卡,但不是作为 '\t' 的规范表示)

Console.Write(ch);
Console.Write(ch.ToString())

猜,Console.Write() 不是正确的做法

【问题讨论】:

  • 您想要所有控件的表示,还是只表示 U+0009?
  • 所有控制字符。我可以很容易地在 Python 中获得它,或者为此甚至在单声道解释器或 VS 的 Roslyn 插件中获得它。但只是无法在控制台窗口中获取它。

标签: c#


【解决方案1】:

不显示控制字符,因为这是控制字符的全部内容。毕竟,在一段文本中放置一个制表符的原因是要有一个制表符。

理想情况下,我们可以使用标准符号␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟␠␡␤␥␦,但它们没有很好的字体支持(现在我看到,删除表格二和替换表格二的符号没有正确显示)这是使用控制台更糟糕。

您的问题也不清楚您是想要规范表示 (U+0009) 还是 C# 转义 (\t),因为您在要求另一个之后立即要求一个(“'的规范表示' \t'")。

假设是后者,我们的问题在于 C# 只为 8 个控制字符提供这样的快捷转义。该过程还要求我们转义 \,原因与 C# 相同 - 我们如何检测 \t 是指制表符,还是表示 \ 后跟 t

因此,假设您想要一个可以直接在 C# 中使用的表单,我们可以执行以下操作:

public static class StringEscaper
{
    public static string EscapeForCSharp(this string str)
    {
        StringBuilder sb = new StringBuilder();
        foreach(char c in str)
            switch(c)
            {
                case '\'': case '"': case '\\':
                    sb.Append(c.EscapeForCSharp());
                    break;
                default:
                    if(char.IsControl(c))
                        sb.Append(c.EscapeForCSharp());
                    else
                        sb.Append(c);
                    break;
            }
        return sb.ToString();
    }
    public static string EscapeForCSharp(this char chr)
    {
        switch(chr)
        {//first catch the special cases with C# shortcut escapes.
            case '\'':
                return @"\'";
            case '"':
                return "\\\"";
            case '\\':
                return @"\\";
            case '\0':
                return @"\0";
            case '\a':
                return @"\a";
            case '\b':
                return @"\b";
            case '\f':
                return @"\f";
            case '\n':
                return @"\n";
            case '\r':
                return @"\r";
            case '\t':
                return @"\t";
            case '\v':
                return @"\v";
            default:
                //we need to escape surrogates with they're single chars,
                //but in strings we can just use the character they produce.
                if(char.IsControl(chr) || char.IsHighSurrogate(chr) || char.IsLowSurrogate(chr))
                    return @"\u" + ((int)chr).ToString("X4");
                else
                    return new string(chr, 1);
        }
    }
}

现在我们可以用一个字符串和一个字符来测试它。

单字符:

Console.WriteLine('\t'.EscapeForCSharp());

输出:

\t

字符串:

string str = "The following string contains all the \"C0\" and \"C1\" controls, escaped with \\ as per C# syntax: "
  + "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F\u007F\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008A\u008B\u008C\u008D\u008E\u008F\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009A\u009B\u009C\u009D\u009E\u009F";
Console.WriteLine(str.EscapeForCSharp());

输出:

The following string contains all the \"C0\" and \"C1\" controls, escaped with \\ as per C# syntax: \0\u0001\u0002\u0003\u0004\u0005\u0006\a\b\t\n\v\f\r\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F\u007F\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008A\u008B\u008C\u008D\u008E\u008F\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009A\u009B\u009C\u009D\u009E\u009F

【讨论】:

  • 我认为规范形式是标准化的 '\t' per this[1],但如果我用词错误,我很抱歉。不过,我了解您关于无法打印不可打印字符的观点。我开始这篇文章的原因是这个简单的实验(由超出范围的原因驱动);在 python 解释器中,我输入a='\x09'str(a) 或者只是a 它显示了'\t'。然后在单声道解释器中输入char ch = '\x09'; ch;,它也会显示'\t'。但我只是无法在 c# 控制台中得到它。无论如何,谢谢你的详尽回答。
  • 在单声道控制台中,您也可以获得一个真实的选项卡。解释器将帮助您调试和尝试事物,因此\t 很有用,但控制台用于实际工作,\t 在大多数情况下都无用(那么您将如何实际输出选项卡?)。 “规范”是指“一种将相同数据的同等有效表示的选择限制为单一无选择格式的方法”。我在上面给出的U+0009 是 Unicode 语言不可知论方式的规范形式,用于表示独立于其字形或缺少字形的字符(因此它对制表符的作用与对 A、B 或 C 一样)...
  • ... 没有规范的 C# 转义,因为 C# 被设计为由人编写而不是作为源文件生成和交换,所以没有必要说 \t 或多或少是规范的\u0009 甚至比 ` ` 直接在源代码中。
  • 感谢您的观点。为 Console 的 0.000001% 的使用率而竞争是愚蠢的。
【解决方案2】:

没有将字符打印为 C# 转义序列的内置方法。

只需根据需要使用字典将字符映射到字符串:

var map = new Dictionary<char, string>{ {'\t', @"\t"}}

并在输出期间使用它来替换字符(如果存在于地图中)。

【讨论】:

  • 这太有趣了。所以我启动了单声道解释器并输入char ch = '\x09'; ch;,然后,boom,我得到的输出是'\t'。不知道为什么这在控制台窗口中如此复杂。
  • 它更复杂,因为控制台窗口设计用于实际输出,而不仅仅是用于调试。 99.99999% 的时间有人将选项卡输出到控制台窗口,这是因为他们想要一个选项卡,而不是一个选项卡的转义。
  • @AntonyThomas,VS 有类似的行为(您可以通过大量“如何从我的字符串中删除转义序列”问题轻松发现)- 即时窗口和调试工具提示/变量视图显示您编码的字符串,但实际的控制台输出不会(因为您真的不希望在命令提示符或所有字符编码的文件中看到文本)。
  • 是的,具有讽刺意味的是,我们经常在这里得到完全相反的问题。
【解决方案3】:

试试这个:

    string tab = "\u0009";
    Console.Write(tab.Replace(tab, "\\t"));

【讨论】:

  • 我无法将它概括为其他控制字符。我应该说清楚的。
【解决方案4】:

\t 有一个特殊的含义(一个标签),所以如果你想打印它,你需要转义'\'。

Console.Writeline("\tHello World");
prints:     Hello World

Console.Writeline("\\tHello World");
prints: \tHello World

您也可以使用@-Syntax 去除\t、\n、\'...的特殊含义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-22
    • 1970-01-01
    • 1970-01-01
    • 2012-07-21
    • 2013-06-30
    相关资源
    最近更新 更多