As others have pointed out, you're calling Substring
with incorrect values. It takes a starting position and a length (and you're passing in an end position).
However, a different way to approach this problem might be to write a method that generates a sign for you, with specific text and a specific width, and then you can simply call that method as many times as you like to generate equal-sized signs.
If we write a method that takes in a string and a width, we can generate a sign accordingly. One question that occurs quickly, however, is what do we do if the string is longer than the width? I think there are two options:
- Truncate the string to fit the width
- Expand the sign to fit the string
So I've added an expandWidth
parameter that, when set to true, expands the sign to accommodate the longest string. If set to false, it will truncate the string.
The rest of the method is fairly self-explanatory: Split the input string on the newline characters in case the sign should have more than one line, determine the longest line we need to display and adjust our sign width if expandWidth
is true
, write out our header string (the top of the sign), use Substring
, PadLeft
, and PadRight
to center each line within the width, and finally write our footer (the bottom of the sign):
public static void WriteSign(string signText, int signWidth = 10, bool expandWidth = true)
{
// Split input into lines, in case there's
// more than one line to display on the sign
var lines = signText
.Split(new[] {'\r', '\n'}, StringSplitOptions.None)
.Select(line => line.Trim());
// Determine the sign width based on the longest line
var actualSignWidth = expandWidth
? Math.Max(lines.Max(l => l.Length), signWidth)
: signWidth;
// Write header
Console.WriteLine("╔" + new string('═', Math.Max(0, actualSignWidth)) + "╗");
// Write lines
foreach (var line in lines)
{
var signLine = line.Substring(0, Math.Min(line.Length, actualSignWidth))
.PadLeft(Math.Min(actualSignWidth, (actualSignWidth + line.Length) / 2))
.PadRight(actualSignWidth);
Console.WriteLine("║" + signLine + "║");
}
// Write footer
Console.WriteLine("╚" + new string('═', Math.Max(0, actualSignWidth)) + "╝");
}
Now we can create a string with \n
characters between each group of words, and we can display them all on one sign, or split them and display a bunch of separate signs.
For example:
private static void Main(string[] cmdArgs)
{
var signText = "If our road signs\nCatch your eye\nSmile\nBut don't forget\nTo buy\nBurma shave";
var splitText = signText.Split('\n');
var signWidth = splitText.Max(line => line.Length) + 2;
// Write a sign with all the lines on one sign
WriteSign(signText, signWidth);
// Write a divider to separate the first sign from the rest
Console.WriteLine(new string('-', Console.WindowWidth));
// Write a separate sign for each line
foreach (var line in splitText) WriteSign(line, signWidth);
GetKeyFromUser("\nDone! Press any key to exit...");
}
Output
