是否可以在 .NET 中以彩色写入控制台?

Is it possible to write to the console in colour in .NET?

提问人:NibblyPig 提问时间:4/30/2010 更新时间:8/7/2023 访问量:241653

问:

编写一个小的命令行工具,以不同的颜色输出会很好。这可能吗?

C# .NET vb.net 颜色

评论


答:

163赞 Darin Dimitrov 4/30/2010 #1
class Program
{
    static void Main()
    {
        Console.BackgroundColor = ConsoleColor.Blue;
        Console.ForegroundColor = ConsoleColor.White;
        Console.WriteLine("White on blue.");
        Console.WriteLine("Another line.");
        Console.ResetColor();
    }
}

取自这里

375赞 Mark Byers 4/30/2010 #2

是的。请参阅此文章。下面是一个示例:

Console.BackgroundColor = ConsoleColor.Blue;
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("White on blue.");

enter image description here

评论

7赞 RollRoll 6/14/2016
可以添加背景图片吗?
0赞 Remigiusz Schoida 3/3/2019
@RollRoll不在默认的 cmd.exe 中。不过,您可以尝试使用控制台模拟器,它支持背景图像调整,但仍然无法以编程方式完成。
76赞 Roger Hill 1/19/2016 #3

以上评论都是可靠的回应,但请注意,它们不是线程安全的。如果要使用多个线程写入控制台,则更改颜色将添加争用条件,从而创建一些看起来奇怪的输出。不过,修复起来很简单:

public class ConsoleWriter
{
    private static object _MessageLock= new object();

    public void WriteMessage(string message)
    {
        lock (_MessageLock)
        {
            Console.BackgroundColor = ConsoleColor.Red;
            Console.WriteLine(message);
            Console.ResetColor();
        }
    }
}

评论

21赞 Joe 7/5/2017
即使没有颜色变化,在没有同步的情况下从多个线程写入也会导致输出乱码:不仅仅是更改颜色会导致争用条件
11赞 BatteryBackupUnit 10/17/2017
@Joe 单次通话不会乱码。请参阅 stackoverflow.com/questions/4812508/...。这只是写调用的顺序,这是不“安全的”。Write
0赞 Kyle Delaney 9/2/2020
但是,如果其他进程正在写入同一控制台呢?他们不会使用您的锁定对象。有没有真正原子化的方法来改变颜色,写到控制台,然后把颜色改回来?
1赞 Roger Hill 9/4/2020
如果您不选择使用控制台编写器,他们将不会使用控制台编写器。这里的含义是,您将此对象用于对控制台的所有写入。我想您可以在 Console.Write 命令上做一些棘手的包装器,但这有点矫枉过正。
0赞 Stewart 12/23/2022
在我看来,这个方法——甚至整个班级——应该是静态的。WriteMessage
19赞 equiman 12/27/2017 #4

是的,这很容易,而且是可能的。定义第一个默认颜色。

Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.White;
Console.Clear();

Console.Clear()为了设置新的控制台颜色,这一点很重要。如果不执行此步骤,则在请求带有 的值时,可以看到组合颜色。Console.ReadLine()

然后,您可以更改每次打印的颜色:

Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Red text over black.");

完成程序后,请记住在完成时重置控制台颜色:

Console.ResetColor();
Console.Clear();

现在有了netcore,如果你想“保留”用户体验,我们还有另一个问题,因为终端在每个操作系统上都有不同的颜色。

我正在制作一个库来解决这个问题的文本格式:颜色、对齐等等。随意使用和贡献。

https://github.com/deinsoftware/colorify/,也可作为 NuGet 包使用

Windows/Linux 的颜色(深色):
enter image description here

MacOS 的颜色(浅色):
enter image description here

5赞 Chamila Maddumage 7/31/2018 #5

是的,可以按以下方式进行。这些颜色可以在控制台应用程序中用于查看红色等错误。

Console.BackgroundColor = ConsoleColor.Blue;
Console.ForegroundColor = ConsoleColor.White;//after this line every text will be white on blue background
Console.WriteLine("White on blue.");
Console.WriteLine("Another line.");
Console.ResetColor();//reset to the defoult colour
63赞 silkfire 12/5/2018 #6

我创建了一个小型插件(在 NuGet 上可用),它允许您向控制台输出添加任何(如果终端支持)颜色,而不受经典解决方案的限制。

它通过扩展对象来工作,语法非常简单:String

"colorize me".Pastel("#1E90FF");

支持前景色和背景色。

enter image description here

评论

4赞 Pang 10/16/2020
我相信这个库使用那些ANSI转义颜色代码,这似乎是Microsoft.Extensions.Logging.Console也在使用的。
2赞 silkfire 10/16/2020
@Pang Microsoft.Extensions.Logging.Console 是一个日志记录库,而 Pastel 可用于直接打印到控制台;此外,它似乎支持我从源代码中得出的有限颜色子集。
1赞 Tono Nam 1/20/2022
@Pang由于某种原因,该库没有实现所有前景色。我倾向于使用Microsoft解决方案,但Pastel解决方案更完整。
8赞 Daap 5/9/2019 #7

只是为了补充上面所有使用的答案:要更改同一行文本的颜色,请写例如:Console.WriteLine

Console.Write("This test ");
Console.BackgroundColor = bTestSuccess ? ConsoleColor.DarkGreen : ConsoleColor.Red;
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine((bTestSuccess ? "PASSED" : "FAILED"));
Console.ResetColor();
22赞 Walter Stabosz 3/3/2020 #8

这是我编写的一个简单的方法,用于编写具有内联颜色更改的控制台消息。它只支持一种颜色,但它符合我的需求。

// usage: WriteColor("This is my [message] with inline [color] changes.", ConsoleColor.Yellow);
static void WriteColor(string message, ConsoleColor color)
{
    var pieces = Regex.Split(message, @"(\[[^\]]*\])");

    for(int i=0;i<pieces.Length;i++)
    {
        string piece = pieces[i];
        
        if (piece.StartsWith("[") && piece.EndsWith("]"))
        {
            Console.ForegroundColor = color;
            piece = piece.Substring(1,piece.Length-2);          
        }
        
        Console.Write(piece);
        Console.ResetColor();
    }
    
    Console.WriteLine();
}

image of a console message with inline color changes

评论

0赞 Leandro Bardelli 4/20/2023
代码很好,但它缺乏解释,你在做什么?
0赞 Walter Stabosz 4/20/2023
你是要我评论代码吗?我认为这是不言自明的。该函数扫描以方括号括起来的文本命名的字符串,并将属性设置为打印出黄色文本,将文本写入控制台,然后将文本重置为默认的 ForegroundColor。我不相信 SO 答案需要这么多细节。对我来说,答案的主要目的是解决问题,而不是教育提问的开发人员。messageConsole.ForegroundColor
0赞 Leandro Bardelli 4/20/2023
我投票赞成答案,但 SO 的主要思想是一个明确的答案,可以向 OP 以外的其他人解释。在这种情况下,答案很好,但与 OP 要求的内容无关。“碎片”是什么意思,即单词?函件?什么是正则表达式?等
0赞 SReza S 3/19/2021 #9

我确实想在我想使用时调整文本颜色所以我不得不写Console.WriteLine();

Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.WriteLine("my message");
Console.ResetColor();

每次我想写点什么

所以我发明了我的方法,并继续在程序类中使用它,而不是WriteLine()Console.WriteLine()

public static void WriteLine(string buffer, ConsoleColor foreground = ConsoleColor.DarkGreen, ConsoleColor backgroundColor = ConsoleColor.Black)
{
   Console.ForegroundColor = foreground;
   Console.BackgroundColor = backgroundColor;
   Console.WriteLine(buffer);
   Console.ResetColor();
}

为了让它更容易,我还写了一个这样的方法:Readline()

public static string ReadLine()
{
   var line = Console.ReadLine();
   return line ?? string.Empty;
}

因此,现在我们必须这样做才能在控制台中编写或读取某些内容:

static void Main(string[] args) {
   WriteLine("hello this is a colored text");
   var answer = Readline();
}
7赞 Rans 7/25/2021 #10

同时为多个单词着色的示例方法。

private static void WriteColor(string str, params (string substring, ConsoleColor color)[] colors)
{
    var words = Regex.Split(str, @"( )");

    foreach (var word in words)
    {
        (string substring, ConsoleColor color) cl = colors.FirstOrDefault(x => x.substring.Equals("{" + word + "}"));
        if (cl.substring != null)
        {
            Console.ForegroundColor = cl.color;
            Console.Write(cl.substring.Substring(1, cl.substring.Length - 2));
            Console.ResetColor();
        }
        else
        {
            Console.Write(word);
        }
    }
}

用法:

WriteColor("This is my message with new color with red", ("{message}", ConsoleColor.Red), ("{with}", ConsoleColor.Blue));

输出:

enter image description here

6赞 Ramin Rahimzada 1/8/2022 #11

我开发了一个名为 cConsole 的小型有趣的类库,用于彩色控制台输出。
用法示例:

const string tom = "Tom";
const string jerry = "Jerry";
CConsole.WriteLine($"Hello {tom:red} and {jerry:green}");

它使用 C# FormattableString、IFormatProvider 和 ICustomFormatter 接口的一些功能来设置文本切片的前景色和背景色。
您可以在此处查看 cConsole 源代码

评论

0赞 KarloX 2/11/2022
谢谢 - 相当不错。但是由于许可证问题,我不能使用。
0赞 Ramin Rahimzada 4/22/2022
别担心。每个人都可以在任何地方使用它,而不会因为生产使用中可能出现的未来问题而责怪我
0赞 Jay Imerman 5/4/2022
老实说,我不知道为什么这没有被点赞一百次!这真的很棒,一个不错的优雅解决方案。
8赞 JobaDiniz 8/8/2022 #12

下面是使用 dotnet 的新字符串插值功能的优雅实现。

[InterpolatedStringHandler]
public ref struct ConsoleInterpolatedStringHandler
{
    private static readonly Dictionary<string, ConsoleColor> colors;
    private readonly IList<Action> actions;

    static ConsoleInterpolatedStringHandler() =>
        colors = Enum.GetValues<ConsoleColor>().ToDictionary(x => x.ToString().ToLowerInvariant(), x => x);

    public ConsoleInterpolatedStringHandler(int literalLength, int formattedCount)
    {
        actions = new List<Action>();
    }

    public void AppendLiteral(string s)
    {
        actions.Add(() => Console.Write(s));
    }

    public void AppendFormatted<T>(T t)
    {
        actions.Add(() => Console.Write(t));
    }

    public void AppendFormatted<T>(T t, string format)
    {
        if (!colors.TryGetValue(format, out var color))
            throw new InvalidOperationException($"Color '{format}' not supported");

        actions.Add(() =>
        {
            Console.ForegroundColor = color;
            Console.Write(t);
            Console.ResetColor();
        });
    }

    internal void WriteLine() => Write(true);
    internal void Write() => Write(false);

    private void Write(bool newLine)
    {
        foreach (var action in actions)
            action();

        if (newLine)
            Console.WriteLine();
    }
}

要使用它,请创建一个类,例如:ExtendedConsole

internal static class ExtendedConsole
{
    public static void WriteLine(ConsoleInterpolatedStringHandler builder)
    {
        builder.WriteLine();
    }

    public static void Write(ConsoleInterpolatedStringHandler builder)
    {
        builder.Write();
    }
}

然后,像这样使用它:

        var @default = "default";
        var blue = "blue";
        var green = "green";
        ExtendedConsole.WriteLine($"This should be {@default}, but this should be {blue:blue} and this should be {green:green}");

enter image description here

16赞 UweBaemayr 12/15/2022 #13

我发现对控制台输出片段进行着色的最简单方法是在 Windows 控制台中使用 ANSI 转义序列

public static int Main(string[] args)
{
    string NL          = Environment.NewLine; // shortcut
    string NORMAL      = Console.IsOutputRedirected ? "" : "\x1b[39m";
    string RED         = Console.IsOutputRedirected ? "" : "\x1b[91m";
    string GREEN       = Console.IsOutputRedirected ? "" : "\x1b[92m";
    string YELLOW      = Console.IsOutputRedirected ? "" : "\x1b[93m";
    string BLUE        = Console.IsOutputRedirected ? "" : "\x1b[94m";
    string MAGENTA     = Console.IsOutputRedirected ? "" : "\x1b[95m";
    string CYAN        = Console.IsOutputRedirected ? "" : "\x1b[96m";
    string GREY        = Console.IsOutputRedirected ? "" : "\x1b[97m";
    string BOLD        = Console.IsOutputRedirected ? "" : "\x1b[1m";
    string NOBOLD      = Console.IsOutputRedirected ? "" : "\x1b[22m";
    string UNDERLINE   = Console.IsOutputRedirected ? "" : "\x1b[4m";
    string NOUNDERLINE = Console.IsOutputRedirected ? "" : "\x1b[24m";
    string REVERSE     = Console.IsOutputRedirected ? "" : "\x1b[7m";
    string NOREVERSE   = Console.IsOutputRedirected ? "" : "\x1b[27m";

    Console.WriteLine($"This is {RED}Red{NORMAL}, {GREEN}Green{NORMAL}, {YELLOW}Yellow{NORMAL}, {BLUE}Blue{NORMAL}, {MAGENTA}Magenta{NORMAL}, {CYAN}Cyan{NORMAL}, {GREY}Grey{NORMAL}! ");
    Console.WriteLine($"This is {BOLD}Bold{NOBOLD}, {UNDERLINE}Underline{NOUNDERLINE}, {REVERSE}Reverse{NOREVERSE}! ");
}

输出:

enter image description here

代码实际上是“正常强度”。有关详细信息,请参阅链接的维基百科页面上的“SGR(选择图形演绎版)参数”部分。NOBOLD

如果输出被重定向,重定向测试可避免将转义序列输出到文件中。如果用户的配色方案不是黑底白字,则不会重置,但如果重要,您可以使用控制台功能在程序的开头和结尾保存/恢复用户的配色方案。

评论

0赞 Michael Hutter 5/17/2023
在 Windows 10(C# 控制台应用程序)中,它会生成非彩色输出“This is ←[91mRed←[39m, ←[92mGreen←[39m, ←[93mYellow←[39m, ←[94mBlue←[39mm”)。你知道它不解释代码的原因是什么吗?
0赞 UweBaemayr 5/18/2023
我没有遇到任何问题。但是,此页面可能会有所帮助。操作方法:在终端中使用 ANSI 颜色:ss64.com/nt/syntax-ansi.html .它提到 Windows 版本 1511 到 1903 需要注册表设置。它建议使用 ENABLE_VIRTUAL_TERMINAL_PROCESSING 标志调用 SetConsoleMode API,或者(不太理想)创建注册表项。尝试从 C# 应用进行 SetConsoleAPI 调用,如果有帮助,请回发。
0赞 UweBaemayr 5/18/2023
我也有一些程序禁用了ANSI输出 - 特别是Windows上的一些GNU应用程序,如UNZIP.EXE,特别是当它们崩溃或我在运行时使用Ctrl + Break时。猜测他们可能会修改控制台的工作方式,并且并不总是在完成后恢复它。
0赞 Michael Hutter 5/17/2023 #14

使用这个简单的 C# 代码,您可以演示所有可能的输出颜色并选择所需的颜色。

enter image description here

Type type = typeof(ConsoleColor);
Console.ForegroundColor = ConsoleColor.White;
foreach (var name in Enum.GetNames(type))
{
    Console.BackgroundColor = (ConsoleColor)Enum.Parse(type, name);
    Console.WriteLine(name);
}
Console.BackgroundColor = ConsoleColor.Black;
foreach (var name in Enum.GetNames(type))
{
    Console.ForegroundColor = (ConsoleColor)Enum.Parse(type, name);
    Console.WriteLine(name);
}