5

The last sentence of my code is a Console.WriteLine with a variable. I would like to have the text between "" to be green and the variable to be red.

I have been trying with Console.Foregroundcolor, but this wasn't successful.

Console.WriteLine("What is your name?");
string name = Console.ReadLine();
Console.WriteLine("Your name is {0}.", name);
Console.ReadKey();
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
Romshteyn
  • 61
  • 1
  • 1
  • 4

9 Answers9

5

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

Caius Jard
  • 72,509
  • 5
  • 49
  • 80
4

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.");

This will output as: Nested colors output

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;
}
Jordan9232
  • 147
  • 8
3

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

enter image description here

Jonathan B.
  • 2,742
  • 1
  • 21
  • 18
2

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
fubo
  • 44,811
  • 17
  • 103
  • 137
2

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);
        }
    }
}

Which gives you enter image description here

For marking only the word 'love' and not 'beloved', you can pass " love " to the method (with spaces) which gives you: enter image description here

Bamdad
  • 726
  • 1
  • 11
  • 28
1

If you wanna make different color to each text on console you should write Console.BackgrundColor and Console.ForeGroundColor before each input and output in consolse. For example:

        Console.BackgroundColor = ConsoleColor.Yellow;
        Console.ForegroundColor = ConsoleColor.Red;

        Console.WriteLine("Enter your name:");

        string name = Console.ReadLine();

        Console.BackgroundColor = ConsoleColor.Green;
        Console.ForegroundColor = ConsoleColor.Yellow;

        Console.WriteLine("Hello, " + name);

        Console.ReadKey();
Umid Kurbanov
  • 174
  • 1
  • 5
1

You could make a method for that:

public void ColoredConsoleWrite(ConsoleColor firstColor, string firstText, ConsoleColor secondColor, string secondText)
{
    Console.ForegroundColor = firstColor;
    Console.Write(firstText);
    Console.ForegroundColor = secondColor;
    Console.WriteLine(secondText);
}

And call it later like this:

ColoredConsoleWrite(ConsoleColor.Green, "Your name is ", ConsoleColor.Red, name);
currarpickt
  • 2,290
  • 4
  • 24
  • 39
1

With this method will be easy to write a line differentiating the sections you want in the color you pick.

public static void WriteLineColored(params (ConsoleColor color, string value)[] values)
{
    Console.Write("\r");
    foreach (var value in values)
    {
        Console.ForegroundColor = value.color;
        Console.Write(value.value);
    }
    Console.Write("\r\n");
    Console.ResetColor();
}

Example:

WriteLineColored((ConsoleColor.Blue, "Hello"), (ConsoleColor.Red, "World"), (ConsoleColor.White, "!"));
1

Just ran across this question while looking for a quick and dirty way to colorize fragments of the console output of an internal tool and I found that the ANSI escape sequences work in the Windows console.

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}! ");
}

The output:

enter image description here

The NOBOLD code is really "normal intensity". See the "SGR (Select Graphic Rendition) parameters" section on the linked wikipedia page for details.

The redirection test avoids outputting escape sequences into a file, should the output be redirected. If the user has a color scheme other than white-on-black, it won't get reset but you could maybe use the Console functions to save/restore the user's color scheme at the beginning and end of the program if that matters.

Leandro Bardelli
  • 10,561
  • 15
  • 79
  • 116
UweBaemayr
  • 1,861
  • 1
  • 18
  • 21
  • unfortunately this results in the literal string: ←[91m Did not figure it out yet. – Stijn Van Antwerpen Jan 29 '23 at 13:04
  • @StijnVanAntwerpen: if "←[91m" is "[91m" then that's what you want -- if you send that to the console, all subsequent characters sent to the console will be red. – UweBaemayr Feb 01 '23 at 21:13
  • well no... I did it exactly like in the answer but on the console it shows ←[91m and nothing in red. – Stijn Van Antwerpen Feb 02 '23 at 15:06
  • @StijnVanAntwerpen: I wonder if this might be a codepage problem. If you type chcp, what code page does it report? No idea if this works if the codepage is something other than 437 or 1252 although I'd expect an to be an regardless of the codepage. – UweBaemayr Feb 03 '23 at 16:26
  • @StijnVanAntwerpen 850 should work. Maybe your program is disabling the virtual terminal sequences. Maybe your program is changing the codepage internally, causing the to be output to the console as some other character. I suggest you take a good look at this article, and possibly the ones around it: https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences. – UweBaemayr Feb 06 '23 at 16:57
  • doesnt work with string format and UTF8 – Leandro Bardelli Apr 19 '23 at 17:47