본문 바로가기

C#/예제 코드

c# DataTable 데이터 이쁘게 출력하기 (콘솔)

사전지식

검색해도 맘에 드는 것이 없어서 직접 소스를 작성하였다.


준비물

.net6.0 이상의 버전

에디터는 vscode or vs2022을 추천.


실습

1. 메서드 작성.

using System.Data;
internal static class DataTableEX
{
    const string No = " №";
    public static void Print(this DataTable table, bool rowNum = false) =>
        Print(table, null, rowNum);
    public static void Print(this DataTable table, int top, bool rowNum = false) =>
        Print(table, top, null, rowNum);
    public static void Print(this DataTable table, string[] col, bool rowNum = false) =>
        Print(table, int.MaxValue, col, rowNum);
    public static void Print(this DataTable table, int top, string[] col, bool rowNum = false)
    {

        if (rowNum == true)
        {
            table = table.Copy();
            table.Columns.Add(No, typeof(int)).SetOrdinal(0);
            Array.ForEach(table.AsEnumerable().Take(top).ToArray(), row =>
            row[No] = table.Rows.IndexOf(row));
        }
       

        DataColumn[] columns = table.Columns.Cast<DataColumn>().ToArray();


        if (col != null)
        {
            if (rowNum == true) col = col.Append(No).ToArray();
            columns = columns.Where(c => col.Contains(c.ColumnName)).ToArray();
        }


        if (columns.Length == 0)
        {
            Console.WriteLine("NO columns");
            return;
        }


        int RealLen(string str) => str.Select(x => (0xFF00 & x) == 0 ? 1 : 2).Sum();
        int UnLen(string str) => str.Select(x => (0xFF00 & x) == 0 ? 0 : 1).Sum();
        int getAlign(Type t) => t.ToString().ToLower() switch
        {
            var x when x.StartsWith("system.byte") => 1,
            var x when x.StartsWith("system.sbyte") => 1,
            var x when x.StartsWith("system.short") => 1,
            var x when x.StartsWith("system.ushort") => 1,
            var x when x.StartsWith("system.int") => 1,
            var x when x.StartsWith("system.uint") => 1,
            var x when x.StartsWith("system.long") => 1,
            var x when x.StartsWith("system.ulong") => 1,
            var x when x.StartsWith("system.float") => 1,
            var x when x.StartsWith("system.double") => 1,
            var x when x.StartsWith("system.decimal") => 1,
            _ => -1
        };
        string Escape(string str) => String.Join("", str.Select(x => x switch
        {
            '\b' => "\\b",
            '\f' => "\\f",
            '\n' => "\\n",
            '\r' => "\\r",
            '\t' => "\\t",
            _ => x.ToString()
        }));


        var colNames = columns.Select(x => Escape(x.ColumnName));

        var colsLen = (from c in columns
                       select (t: table.AsEnumerable(), l: RealLen(Escape(c.ColumnName)), c) into o
                       select o.t.Count() == 0
                       ? o.l : o.t.Take(top).Max(x => Math.Max(o.l, RealLen("" + x.Field<object>(o.c))))
                      ).ToArray();

        var align = columns.Select(x => getAlign(x.DataType)).Select((al, i) =>
                         new Func<string, string>(str =>
                         String.Format($"{{0,{al * (colsLen[i] - UnLen("" + str))}}}", str))).ToArray();


        string PadBoth(string source, int length)
        {
            int spaces = length - RealLen(source);
            return new String(' ', spaces / 2) + source + new string(' ', spaces - spaces / 2);
        }


        Action<string> WL = Console.WriteLine;
        var preBg = Console.BackgroundColor;
        Console.BackgroundColor = ConsoleColor.DarkCyan;
        WL(PadBoth(table.TableName, (colsLen.Sum() + colNames.Count() * 3 + 2)));
        Console.BackgroundColor = preBg;


        WL($"┌{  String.Join('┬',  colsLen.Select(x => new String('-', x + 2)))                  }┐");
        WL($"│ {String.Join(" │ ", colNames.Select((x, i) => x.PadRight(colsLen[i] - UnLen(x))))} │");
        WL($"├{  String.Join('┼',  colsLen.Select(x => new String('-', x + 2)))                  }┤");
        Array.ForEach(table.AsEnumerable().Take(top).ToArray(), r =>
        WL($"│ {String.Join(" │ ", columns.Select((x, i) => align[i](Escape("" + r[x]))))       } │"));
        WL($"└{  String.Join('┴',  colsLen.Select(x => new String('-', x + 2)))                  }┘");

        Console.WriteLine();
    }
}

2. 테스트 소스 작성.

※ .net6.0 ( C#10.0 에서는 Main()을 생략한다 )

using System.Data;
using System.Text;
 
Console.OutputEncoding = System.Text.Encoding.UTF8;
 
var dt = new DataTable("안농");
dt.Columns.Add("숫자", typeof(double)).AllowDBNull = false;
dt.Columns.Add("가나\n다", typeof(int));
dt.Columns.Add("문자");
dt.Columns.Add("날짜", typeof(DateTime));
dt.Rows.Add(new object[] { 11, 2, "맏을 수 없을만큼", DateTime.Now });
dt.Rows.Add(new object[] { 22, 41, "돌아버린 사람인지...", DateTime.Now });
dt.Rows.Add(new object[] { 3, 4, "저는 실패할래야", DateTime.Now });
dt.Rows.Add(new object[] { 4, 2, "실패할 수가 없습니다.", DateTime.Now });
dt.Rows.Add(new object[] { 5, 41, "여러분이 계신데", DateTime.Now });
dt.Rows.Add(new object[] { 446, 4, "제가 어떻게 실패할 수 있습니까", DateTime.Now });

dt.Print(5, new[] { "숫자", "문자", "날짜"}, true );

vs2022 console


주의사항 및 후기

콘솔 창의 폰트는 돋움체나 굴림체 같은 체(體)로 끝나는.. 크기가 고정적인 폰트를 사용해야 포맷이 깨지지 않는다.

vscode는 기본 폰트가 고정적이 아니므로 설정> 기능> 디버그> Font Family 에서 GulimChe로 바꾸는 것을 추천한다.

그리고 특정 외국 글자는 표현이 안되거나 포맷이 깨진다. 

전각과 반각의 규칙을 1바이트 초과 유무로 구분 지었는데, 그 예상을 뛰 넘는 글자가 있다 (예:태국어)

 

Console.OutputEncoding = System.Text.Encoding.UTF8  이 구문을 빼면 특정 문자가 깨진다.

콘솔 창은 기본적으로 UTF8이 아니기 때문이다.

 

UTF8로 바꾸는 다른 방법들 :

2021.12.30 - [C#] - 콘솔창 UTF 8 로 바꾸기 (win 10에서 4가지 방법)

 

좀 더 정확한 반각문자를 알고 싶다면:

2021.12.31 - [C#/예제 코드] - c# 전각 or 반각 문자 전부 찾기 (콘솔)

 

c#으로 폰트(글꼴)을 바꾸고 싶다면:

2022.01.01 - [C#/예제 코드] - c# 콘솔 폰트 확인 및 폰트(글꼴,크기) 변경

 

👩자매품👧 컬럼 정보 출력:

2021.12.30 - [C#/예제 코드] - c# DataTable 컬럼정보 이쁘게 출력하기 (콘솔)

 

 

출처 https://self-edu.tistory.com/ (myself)