【问题标题】:How can I align text in columns using Console.WriteLine?如何使用 Console.WriteLine 对齐列中的文本?
【发布时间】:2011-05-25 20:13:35
【问题描述】:

我有一种列显示,但最后两列似乎没有正确对齐。这是我目前拥有的代码:

Console.WriteLine("Customer name    " 
    + "sales          " 
    + "fee to be paid    " 
    + "70% value       " 
    + "30% value");
for (int DisplayPos = 0; DisplayPos < LineNum; DisplayPos = DisplayPos + 1)
{
    seventy_percent_value = ((fee_payable[DisplayPos] / 10.0) * 7);
    thirty_percent_value = ((fee_payable[DisplayPos] / 10.0) * 3);          
    Console.WriteLine(customer[DisplayPos] + "         " 
        + sales_figures[DisplayPos] + "               " 
        + fee_payable[DisplayPos] + "           " 
        + seventy_percent_value + "           " 
        + thirty_percent_value);
}

【问题讨论】:

  • See here 获取此问题的更通用版本。那里的答案也值得一试。

标签: c# console tabs alignment vertical-alignment


【解决方案1】:

对齐可以与字符串插值结合,放在':'格式字符前面。

Console.WriteLine($"{name,40} {MaterialArea,10:N2}m² {MaterialWeightInLbs,10:N0}lbs {Cost,10:C2}");

【讨论】:

    【解决方案2】:

    做一些填充,即

              public static void prn(string fname, string fvalue)
                {
                    string outstring = fname.PadRight(20)  +"\t\t  " + fvalue;
                    Console.WriteLine(outstring);
    
                }
    
    

    这很好,至少对我来说。

    【讨论】:

      【解决方案3】:

      我真的很喜欢这里提到的那些库,但我有一个想法,它可能比仅仅填充或进行大量字符串操作更简单,

      您可以使用数据的最大字符串长度手动设置光标。这里有一些代码来得到这个想法(未经测试):

      var column1[] = {"test", "longer test", "etc"}
      var column2[] = {"data", "more data", "etc"}
      var offset = strings.OrderByDescending(s => s.Length).First().Length;
      for (var i = 0; i < column.Length; i++) {
          Console.Write(column[i]);
          Console.CursorLeft = offset + 1;
          Console.WriteLine(column2[i]);
      }
      

      如果您有更多行,您可以轻松推断。

      【讨论】:

        【解决方案4】:

        有几个 NuGet 包可以帮助格式化。在某些情况下,string.Format 的功能就足够了,但您可能希望至少根据内容自动调整列大小。

        ConsoleTableExt

        ConsoleTableExt 是一个简单的库,它允许格式化表格,包括没有网格线的表格。 (一个更流行的包ConsoleTables 似乎不支持无边框表格。)下面是一个格式化对象列表的示例,其列的大小基于其内容:

        ConsoleTableBuilder
            .From(orders
                .Select(o => new object[] {
                    o.CustomerName,
                    o.Sales,
                    o.Fee,
                    o.Value70,
                    o.Value30
                })
                .ToList())
            .WithColumn(
                "Customer",
                "Sales",
                "Fee",
                "70% value",
                "30% value")
            .WithFormat(ConsoleTableBuilderFormat.Minimal)
            .WithOptions(new ConsoleTableBuilderOption { DividerString = "" })
            .ExportAndWriteLine();
        

        CsConsoleFormat

        如果您需要更多功能,可以使用CsConsoleFormat 实现任何控制台格式。† 例如,这里将对象列表的格式设置为固定列宽为 10 的网格,就像在其他答案中使用 @ 987654326@:

        ConsoleRenderer.RenderDocument(
            new Document { Color = ConsoleColor.Gray }
                .AddChildren(
                    new Grid { Stroke = LineThickness.None }
                        .AddColumns(10, 10, 10, 10, 10)
                        .AddChildren(
                            new Div("Customer"),
                            new Div("Sales"),
                            new Div("Fee"),
                            new Div("70% value"),
                            new Div("30% value"),
                            orders.Select(o => new object[] {
                                new Div().AddChildren(o.CustomerName),
                                new Div().AddChildren(o.Sales),
                                new Div().AddChildren(o.Fee),
                                new Div().AddChildren(o.Value70),
                                new Div().AddChildren(o.Value30)
                            })
                        )
                ));
        

        它可能看起来比纯string.Format 更复杂,但现在可以自定义。例如:

          1234563 )。
        • 如果要将数字列向右对齐,请将{ Align = Right } 添加到单元格的初始化程序中。

        • 如果要为列着色,请将{ Color = Yellow } 添加到单元格的初始化程序中。

        • 您可以更改边框样式等等。

        †​​ CsConsoleFormat 是我开发的。

        【讨论】:

          【解决方案5】:

          只是为了添加到 roya 的答案。在 c# 6.0 中,您现在可以使用字符串插值:

          Console.WriteLine($"{customer[DisplayPos],10}" +
                            $"{salesFigures[DisplayPos],10}" +
                            $"{feePayable[DisplayPos],10}" +
                            $"{seventyPercentValue,10}" +
                            $"{thirtyPercentValue,10}");
          

          这实际上可以是一行而不需要额外的钱,我只是认为这样更容易阅读。

          您还可以在 System.Console 上使用静态导入,允许您这样做:

          using static System.Console;
          
          WriteLine(/* write stuff */);
          

          【讨论】:

          【解决方案6】:

          我知道,很老的线程,但是当周围有更长的字符串时,建议的解决方案不是全自动的。

          因此,我创建了一个完全自动化的小型辅助方法。只需传入一个字符串数组列表,其中每个数组代表一条线,数组中的每个元素,以及线的一个元素。

          方法可以这样使用:

          var lines = new List<string[]>();
          lines.Add(new[] { "What", "Before", "After"});
          lines.Add(new[] { "Name:", name1, name2});
          lines.Add(new[] { "City:", city1, city2});
          lines.Add(new[] { "Zip:", zip1, zip2});
          lines.Add(new[] { "Street:", street1, street2});
          var output = ConsoleUtility.PadElementsInLines(lines, 3);
          

          辅助方法如下:

          public static class ConsoleUtility
          {
              /// <summary>
              /// Converts a List of string arrays to a string where each element in each line is correctly padded.
              /// Make sure that each array contains the same amount of elements!
              /// - Example without:
              /// Title Name Street
              /// Mr. Roman Sesamstreet
              /// Mrs. Claudia Abbey Road
              /// - Example with:
              /// Title   Name      Street
              /// Mr.     Roman     Sesamstreet
              /// Mrs.    Claudia   Abbey Road
              /// <param name="lines">List lines, where each line is an array of elements for that line.</param>
              /// <param name="padding">Additional padding between each element (default = 1)</param>
              /// </summary>
              public static string PadElementsInLines(List<string[]> lines, int padding = 1)
              {
                  // Calculate maximum numbers for each element accross all lines
                  var numElements = lines[0].Length;
                  var maxValues = new int[numElements];
                  for (int i = 0; i < numElements; i++)
                  {
                      maxValues[i] = lines.Max(x => x[i].Length) + padding;
                  }
                  var sb = new StringBuilder();
                  // Build the output
                  bool isFirst = true;
                  foreach (var line in lines)
                  {
                      if (!isFirst)
                      {
                          sb.AppendLine();
                      }
                      isFirst = false;
                      for (int i = 0; i < line.Length; i++)
                      {
                          var value = line[i];
                          // Append the value with padding of the maximum length of any value for this element
                          sb.Append(value.PadRight(maxValues[i]));
                      }
                  }
                  return sb.ToString();
              }
          }
          

          希望这对某人有所帮助。来源来自我博客中的一篇文章:http://dev.flauschig.ch/wordpress/?p=387

          【讨论】:

          • 这是最准确的答案。尽管如此,我已经改进了最后一行的方法,它并不总是声明所有行:pastebin.com/CVkavHgy
          • 如果您使用 Console.Write 打印“输出”,您可以摆脱 isFirst 部分。只需在 foreach 末尾执行 sb.AppendLine(); 即可。
          【解决方案7】:

          试试这个

          Console.WriteLine("{0,10}{1,10}{2,10}{3,10}{4,10}",
            customer[DisplayPos],
            sales_figures[DisplayPos],
            fee_payable[DisplayPos], 
            seventy_percent_value,
            thirty_percent_value);
          

          其中大括号内的第一个数字是索引,第二个是对齐方式。第二个数字的符号表示字符串应该左对齐还是右对齐。使用负数左对齐。

          或者看看 http://msdn.microsoft.com/en-us/library/aa331875(v=vs.71).aspx

          【讨论】:

          • 其实你不需要传递 string.format 方法。换句话说,这将是同样的事情:Console.WriteLine("{0,10}{1,10}{2,10}{3,10}{4,10}", customer[DisplayPos], sales_figures[DisplayPos], fee_payable[DisplayPos], seventy_percent_value, thirty_percent_value);
          【解决方案8】:

          您应该将实际的制表符(\t 转义序列)嵌入到每个输出字符串中,而不是尝试手动将文本对齐到具有任意空格字符串的列中:

          Console.WriteLine("Customer name" + "\t"
              + "sales" + "\t" 
              + "fee to be paid" + "\t" 
              + "70% value" + "\t" 
              + "30% value");
          for (int DisplayPos = 0; DisplayPos < LineNum; DisplayPos++)
          {
              seventy_percent_value = ((fee_payable[DisplayPos] / 10.0) * 7);
              thirty_percent_value = ((fee_payable[DisplayPos] / 10.0) * 3);          
              Console.WriteLine(customer[DisplayPos] + "\t" 
                  + sales_figures[DisplayPos] + "\t" 
                  + fee_payable + "\t\t"
                  + seventy_percent_value + "\t\t" 
                  + thirty_percent_value);
          }
          

          【讨论】:

          • 只有当您的数据长度相似时,选项卡才能正常工作。如果您有不同长度的数据,您应该使用带有格式字符串的 royas 答案。
          • 是的,他的答案要好得多。我一看到它就投了赞成票,但留下了我的,以防万一更简单的方法更有效。不过,我不确定为什么我的被接受了... :-)
          • 别忘了 string.PadRight() 和 string.PadLeft()
          • 如果您尝试将文本与可变字体宽度对齐,royas 的回答没有帮助。我认为您需要将填充与this answer 中的选项卡结合使用。
          【解决方案9】:

          您可以使用制表符代替列之间的空格,和/或在格式字符串中设置列的最大大小...

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-07-10
            • 2011-05-02
            • 1970-01-01
            • 2012-09-21
            • 2015-09-02
            • 2011-03-29
            • 1970-01-01
            相关资源
            最近更新 更多