zoukankan      html  css  js  c++  java
  • C# Tips: Draw a data table in console

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Threading.Tasks;
      6 
      7     namespace datatable
      8     {
      9         public class ConsoleTable
     10         {
     11             /// <summary>  
     12             /// This will hold the header of the table.  
     13             /// </summary>  
     14             private string[] header;
     15 
     16             /// <summary>  
     17             /// This will hold the rows (lines) in the table, not including the  
     18             /// header. I'm using a List of lists because it's easier to deal with...  
     19             /// </summary>  
     20             private List<List<string>> rows;
     21 
     22             /// <summary>  
     23             /// This is the default element (character/string) that will be put  
     24             /// in the table when user adds invalid data, example:  
     25             ///     ConsoleTable ct = new ConsoleTable();  
     26             ///     ct.AddRow(new List<string> { null, "bla", "bla" });  
     27             /// That null will be replaced with "DefaultElement", also, empty  
     28             /// strings will be replaced with this value.  
     29             /// </summary>  
     30             private const string DefaultElement = "X";
     31 
     32             public enum AlignText
     33             {
     34                 ALIGN_RIGHT,
     35                 ALIGN_LEFT,
     36             }
     37 
     38             public ConsoleTable()
     39             {
     40                 header = null;
     41                 rows = new List<List<string>>();
     42                 TextAlignment = AlignText.ALIGN_LEFT;
     43             }
     44 
     45             /// <summary>  
     46             /// Set text alignment in table cells, either RIGHT or LEFT.  
     47             /// </summary>  
     48             public AlignText TextAlignment
     49             {
     50                 get;
     51                 set;
     52             }
     53 
     54             public void SetHeaders(string[] h)
     55             {
     56                 header = h;
     57             }
     58 
     59             public void AddRow(List<string> row)
     60             {
     61                 rows.Add(row);
     62             }
     63 
     64             private void AppendLine(StringBuilder hsb, int length)
     65             {
     66                 // " " length is 1  
     67                 // "
    " length is 2  
     68                 // +1 length because I want the output to be prettier  
     69                 // Hence the length - 4 ...  
     70                 hsb.Append(" ");
     71                 hsb.Append(new string('-', length - 4));
     72                 hsb.Append("
    ");
     73             }
     74 
     75             /// <summary>  
     76             /// This function returns the maximum possible length of an  
     77             /// individual row (line). Of course that if we use table header,  
     78             /// the maximum length of an individual row should equal the  
     79             /// length of the header.  
     80             /// </summary>  
     81             private int GetMaxRowLength()
     82             {
     83                 if (header != null)
     84                     return header.Length;
     85                 else
     86                 {
     87                     int maxlen = rows[0].Count;
     88                     for (int i = 1; i < rows.Count; i++)
     89                         if (rows[i].Count > maxlen)
     90                             maxlen = rows[i].Count;
     91 
     92                     return maxlen;
     93                 }
     94             }
     95 
     96             private void PutDefaultElementAndRemoveExtra()
     97             {
     98                 int maxlen = GetMaxRowLength();
     99 
    100                 for (int i = 0; i < rows.Count; i++)
    101                 {
    102                     // If we find a line that is smaller than the biggest line,  
    103                     // we'll add DefaultElement at the end of that line. In the end  
    104                     // the line will be as big as the biggest line.  
    105                     if (rows[i].Count < maxlen)
    106                     {
    107                         int loops = maxlen - rows[i].Count;
    108                         for (int k = 0; k < loops; k++)
    109                             rows[i].Add(DefaultElement);
    110                     }
    111                     else if (rows[i].Count > maxlen)
    112                     {
    113                         // This will apply only when header != null, and we try to  
    114                         // add a line bigger than the header line. Remove the elements  
    115                         // of the line, from right to left, until the line is equal  
    116                         // with the header line.  
    117                         rows[i].RemoveRange(maxlen, rows[i].Count - maxlen);
    118                     }
    119 
    120                     // Find bad data, loop through all table elements.  
    121                     for (int j = 0; j < rows[i].Count; j++)
    122                     {
    123                         if (rows[i][j] == null)
    124                             rows[i][j] = DefaultElement;
    125                         else if (rows[i][j] == "")
    126                             rows[i][j] = DefaultElement;
    127                     }
    128                 }
    129             }
    130 
    131             /// <summary>  
    132             /// This function will return an array of integers, an element at  
    133             /// position 'i' will return the maximum length from column 'i'  
    134             /// of the table (if we look at the table as a matrix).  
    135             /// </summary>  
    136             private int[] GetWidths()
    137             {
    138                 int[] widths = null;
    139                 if (header != null)
    140                 {
    141                     // Initially we assume that the maximum length from column 'i'  
    142                     // is exactly the length of the header from column 'i'.  
    143                     widths = new int[header.Length];
    144                     for (int i = 0; i < header.Length; i++)
    145                         widths[i] = header[i].ToString().Length;
    146                 }
    147                 else
    148                 {
    149                     int count = GetMaxRowLength();
    150                     widths = new int[count];
    151                     for (int i = 0; i < count; i++)
    152                         widths[i] = -1;
    153                 }
    154 
    155                 foreach (List<string> s in rows)
    156                 {
    157                     for (int i = 0; i < s.Count; i++)
    158                     {
    159                         s[i] = s[i].Trim();
    160                         if (s[i].Length > widths[i])
    161                             widths[i] = s[i].Length;
    162                     }
    163                 }
    164 
    165                 return widths;
    166             }
    167 
    168             /// <summary>  
    169             /// Returns a valid format that is to be passed to AppendFormat  
    170             /// member function of StringBuilder.  
    171             /// General form: "|{i, +/-widths[i]}|", where 0 <= i <= widths.Length - 1  
    172             /// and widths[i] represents the maximum width from column 'i'.  
    173             /// </summary>  
    174             /// <param name="widths">The array of widths presented above.</param>  
    175             private string BuildRowFormat(int[] widths)
    176             {
    177                 string rowFormat = String.Empty;
    178                 for (int i = 0; i < widths.Length; i++)
    179                 {
    180                     if (TextAlignment == AlignText.ALIGN_LEFT)
    181                         rowFormat += "| {" + i.ToString() + ",-" + (widths[i]) + "} ";
    182                     else
    183                         rowFormat += "| {" + i.ToString() + "," + (widths[i]) + "} ";
    184                 }
    185 
    186                 rowFormat = rowFormat.Insert(rowFormat.Length, "|
    ");
    187                 return rowFormat;
    188             }
    189 
    190             /// <summary>  
    191             /// Prints the table, main function.  
    192             /// </summary>  
    193             public void PrintTable()
    194             {
    195                 if (rows.Count == 0)
    196                 {
    197                     Console.WriteLine("Can't create a table without any rows.");
    198                     return;
    199                 }
    200                 PutDefaultElementAndRemoveExtra();
    201 
    202                 int[] widths = GetWidths();
    203                 string rowFormat = BuildRowFormat(widths);
    204 
    205                 // I'm using a temporary string builder to find the total width  
    206                 // of the table, and increase BufferWidth of Console if necessary.  
    207                 StringBuilder toFindLen = new StringBuilder();
    208                 toFindLen.AppendFormat(rowFormat, (header == null ? rows[0].ToArray() : header));
    209                 int length = toFindLen.Length;
    210                 if (Console.BufferWidth < length)
    211                     Console.BufferWidth = length;
    212 
    213                 // Print the first row, or header (if it exist), you can see that AppendLine  
    214                 // is called before/after every AppendFormat.  
    215                 StringBuilder hsb = new StringBuilder();
    216                 AppendLine(hsb, length);
    217                 hsb.AppendFormat(rowFormat, (header == null ? rows[0].ToArray() : header));
    218                 AppendLine(hsb, length);
    219 
    220                 // If header does't exist, we start from 1 because the first row  
    221                 // was already printed above.  
    222                 int idx = 0;
    223                 if (header == null)
    224                     idx = 1;
    225                 for (int i = idx; i < rows.Count; i++)
    226                 {
    227                     hsb.AppendFormat(rowFormat, rows[i].ToArray());
    228                     AppendLine(hsb, length);
    229                 }
    230 
    231                 Console.WriteLine(hsb.ToString());
    232             }
    233 
    234 
    235             static void Main(string[] args)
    236             {
    237                 // Some test table, with header, and 3 lines by 3 columns.  
    238                 ConsoleTable ct = new ConsoleTable();
    239                 ct.TextAlignment = ConsoleTable.AlignText.ALIGN_RIGHT;
    240                 ct.SetHeaders(new string[] { "ID", "Name", "City" });
    241                 ct.AddRow(new List<string> { "1", "John", "New York" });
    242                 ct.AddRow(new List<string> { "2", "Mark", "Washington" });
    243                 ct.AddRow(new List<string> { "3", "Alice", "Chicago" });
    244                 ct.PrintTable();  
    245         }
    246     }
    247   }
  • 相关阅读:
    二叉树前、中、后遍历
    程序员节宜冒泡
    HashMap源码分析
    Stack源码解析
    逆袭之旅DAY24.XIA.二重进阶、双色球
    逆袭之旅DAY24.XIA.数组练习
    LY.JAVA面向对象编程.内部类
    LY.JAVA面向对象编程.修饰符
    LY.JAVA面向对象编程.包的概述、导包
    XIA.人机猜拳
  • 原文地址:https://www.cnblogs.com/zcwvictor-2012/p/3160034.html
Copyright © 2011-2022 走看看