問題描述
如何在控制台應用程序的 Console.WriteLine 中為不同顏色的單詞著色? (How to color words in different colours in a Console.WriteLine in a console application?)
我的代碼的最後一句是一個帶有變量的Console.WriteLine
。我想讓 ""
之間的文本為綠色,變量為紅色。
我一直在嘗試使用 Console.Foregroundcolor
,但這並不成功。
Console.WriteLine("What is your name?");
string name = Console.ReadLine();
Console.WriteLine("Your name is {0}.", name);
Console.ReadKey();
參考解法
方法 1:
An slight improvement on currarpickt's answer:
public void Write(params object[] oo)
{
foreach(var o in oo)
if(o == null)
Console.ResetColor();
else if(o is ConsoleColor)
Console.ForegroundColor = o as ConsoleColor;
else
Console.Write(o.ToString());
}
Now you can mix any number of text and color:
Write("how about ", ConsoleColor.Red, "red", null, " text or how about ", ConsoleColor.Green, "green", null, " text");
Using null puts the color back to default
Or how about we build a parser:
public void Write(string msg)
{
string[] ss = msg.Split('{','}');
ConsoleColor c;
foreach(var s in ss)
if(s.StartsWith("/"))
Console.ResetColor();
else if(s.StartsWith("=") && Enum.TryParse(s.Substring(1), out c))
Console.ForegroundColor = c;
else
Console.Write(s);
}
And we can use like:
Write("how about {=Red}this in red{/} or this in {=Green}green{/} eh?");
Should tidy things up. It's a really simple unsophisticated parser though, you'll need to improve it if your strings contain { or } for example
方法 2:
I liked Caius Jard's parser answer, but I improved upon it a little bit so you can change both the background color and the foreground color, and even nest colors. I've created a new static class called ConsoleWriter.
To set foreground color:
ConsoleWriter.WriteLine("{FC=Red}This text will be red.{/FC}");
To set background color:
ConsoleWriter.WriteLine("{BC=Blue}This background will be blue.{/BC}");
It even keeps track of the history of colors you used in a single call, that way you can actually nest colors like this:
ConsoleWriter.WriteLine("{FC=Magenta}This is magenta, {FC=Yellow}now yellow, {/FC}now back to magenta{/FC}, now back to default.");
I even like to use the actual enum in an interpolated string and it still works:
ConsoleWriter.WriteLine($"{{FC={ConsoleColor.Red}}}This works too!{{/FC}}");
public static void Write(string msg)
{
if (string.IsNullOrEmpty(msg))
{
return;
}
var color_match = Regex.Match(msg, @"{[FB]C=[a‑z]+}|{\/[FB]C}", RegexOptions.IgnoreCase);
if (color_match.Success)
{
var initial_background_color = Console.BackgroundColor;
var initial_foreground_color = Console.ForegroundColor;
var background_color_history = new List<ConsoleColor>();
var foreground_color_history = new List<ConsoleColor>();
var current_index = 0;
while (color_match.Success)
{
if ((color_match.Index ‑ current_index) > 0)
{
Console.Write(msg.Substring(current_index, color_match.Index ‑ current_index));
}
if (color_match.Value.StartsWith("{BC=", StringComparison.OrdinalIgnoreCase)) // set background color
{
var background_color_name = GetColorNameFromMatch(color_match);
Console.BackgroundColor = GetParsedColorAndAddToHistory(background_color_name, background_color_history, initial_background_color);
}
else if (color_match.Value.Equals("{/BC}", StringComparison.OrdinalIgnoreCase)) // revert background color
{
Console.BackgroundColor = GetLastColorAndRemoveFromHistory(background_color_history, initial_background_color);
}
else if (color_match.Value.StartsWith("{FC=", StringComparison.OrdinalIgnoreCase)) // set foreground color
{
var foreground_color_name = GetColorNameFromMatch(color_match);
Console.ForegroundColor = GetParsedColorAndAddToHistory(foreground_color_name, foreground_color_history, initial_foreground_color);
}
else if (color_match.Value.Equals("{/FC}", StringComparison.OrdinalIgnoreCase)) // revert foreground color
{
Console.ForegroundColor = GetLastColorAndRemoveFromHistory(foreground_color_history, initial_foreground_color);
}
current_index = color_match.Index + color_match.Length;
color_match = color_match.NextMatch();
}
Console.Write(msg.Substring(current_index));
Console.BackgroundColor = initial_background_color;
Console.ForegroundColor = initial_foreground_color;
}
else
{
Console.Write(msg);
}
}
public static void WriteLine(string msg)
{
Write(msg);
Console.WriteLine();
}
private static string GetColorNameFromMatch(Match match)
{
return match.Value.Substring(4, match.Value.IndexOf("}") ‑ 4);
}
private static ConsoleColor GetParsedColorAndAddToHistory(string colorName, List<ConsoleColor> colorHistory, ConsoleColor defaultColor)
{
var new_color = Enum.TryParse<ConsoleColor>(colorName, true, out var parsed_color) ? parsed_color : defaultColor;
colorHistory.Add(new_color);
return new_color;
}
private static ConsoleColor GetLastColorAndRemoveFromHistory(List<ConsoleColor> colorHistory, ConsoleColor defaultColor)
{
if (colorHistory.Any())
{
colorHistory.RemoveAt(colorHistory.Count ‑ 1);
}
return colorHistory.Any() ? colorHistory.Last() : defaultColor;
}
方法 3:
You can't use different colors within one Console.WriteLine()
‑ use Console.Write()
instead.
Console.WriteLine("What is your name?");
string name = Console.ReadLine();
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("Your name is ");
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("name");
Console.WriteLine(); //linebreak
Console.ResetColor(); //reset to default values
方法 4:
It looks like Spectre Console does a lot of this magic for us and is inspired by the popular Rich Python library that does a similar thing.
Install Spectre Console:
dotnet add package Spectre.Console
Then use markup to specify colors inline, for example:
using Spectre.Console;
AnsiConsole.Markup("[maroon on blue]Hello[/]");
See documentation for more details: https://spectreconsole.net/markup
方法 5:
Another more reusable way is:
static void Main(string[] args)
{
Write("True love is love for C#, my beloved programming language.", "love");
Console.ReadLine();
}
static void Write(string text, string coloredWord)
{
string[] normalParts = text.Split(new string[] { coloredWord }, StringSplitOptions.None);
for (int i = 0; i < normalParts.Length; i++)
{
Console.ResetColor();
Console.Write(normalParts[i]);
if (i != normalParts.Length ‑ 1)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(coloredWord);
}
}
}
For marking only the word 'love' and not 'beloved', you can pass " love "
to the method (with spaces) which gives you:
(by Romshteyn、Caius Jard、Jordan9232、fubo、Jonathan B.、Bamdad)