From ce7f6b765821299b0e254275f64f3a406a31ed4e Mon Sep 17 00:00:00 2001 From: Artem Yurchenko Date: Mon, 11 Apr 2022 21:02:39 +0200 Subject: [PATCH 1/3] AsciiTableGenerator class was fully refactored --- AsciiTableGenerator.cs | 156 ++++++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 80 deletions(-) diff --git a/AsciiTableGenerator.cs b/AsciiTableGenerator.cs index bfe25c6..3de60f4 100644 --- a/AsciiTableGenerator.cs +++ b/AsciiTableGenerator.cs @@ -1,92 +1,88 @@ -using System.Collections.Generic; -using System.Data; +using System.Data; using System.Globalization; -using System.Linq; using System.Text; namespace AsciiTableGenerators { - public class AsciiTableGenerator - { - public static StringBuilder CreateAsciiTableFromDataTable(DataTable table) - { - var lenghtByColumnDictionary = GetTotalSpaceForEachColumn(table); + public static class AsciiTableGenerator + { + private const string COLUMN_SEPARATOR = " | "; + private const string ALIGN_CHAR = " "; + private const string HEADER_SEPARATOR = "-"; + + public static StringBuilder CreateAsciiTableFromDataTable(DataTable table) + { + var tableBuilder = new StringBuilder(); + var lengthByColumn = GetLengthByColumn(table); + AppendColumns(table, tableBuilder, lengthByColumn); + AppendRows(table, tableBuilder, lengthByColumn); - var tableBuilder = new StringBuilder(); - AppendColumns(table, tableBuilder, lenghtByColumnDictionary); - AppendRows(table, lenghtByColumnDictionary, tableBuilder); - return tableBuilder; - } + return tableBuilder; + } - private static void AppendRows(DataTable table, IReadOnlyDictionary lenghtByColumnDictionary, - StringBuilder tableBuilder) - { - for (var i = 0; i < table.Rows.Count; i++) - { - var rowBuilder = new StringBuilder(); - for (var j = 0; j < table.Columns.Count; j++) - { - rowBuilder.Append(PadWithSpaceAndSeperator(table.Rows[i][j].ToString().Trim(), - lenghtByColumnDictionary[j])); - } - tableBuilder.AppendLine(rowBuilder.ToString()); - } - } + private static Dictionary GetLengthByColumn(DataTable table) + { + var lengthByColumn = new Dictionary(); - private static void AppendColumns(DataTable table, StringBuilder builder, - IReadOnlyDictionary lenghtByColumnDictionary) - { - for (var i = 0; i < table.Columns.Count; i++) - { - var columName = table.Columns[i].ColumnName.Trim(); - var paddedColumNames = PadWithSpaceAndSeperator(ToTitleCase(columName), lenghtByColumnDictionary[i]); - builder.Append(paddedColumNames); - } - builder.AppendLine(); - builder.AppendLine(string.Join("", Enumerable.Repeat("-", builder.ToString().Length - 3).ToArray())); - } + for (var columnIndex = 0; columnIndex < table.Columns.Count; columnIndex++) + { + var rowsLengths = new int[table.Rows.Count]; - private static string ToTitleCase(string columnName) - { - return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(columnName.Replace("_", " ")); - } + for (var rowIndex = 0; rowIndex < table.Rows.Count; rowIndex++) + { + rowsLengths[rowIndex] = table.Rows[rowIndex][columnIndex].ToString()?.Trim().Length ?? 0; + } - private static Dictionary GetTotalSpaceForEachColumn(DataTable table) - { - var lengthByColumn = new Dictionary(); - for (var i = 0; i < table.Columns.Count; i++) - { - var length = new int[table.Rows.Count]; - for (var j = 0; j < table.Rows.Count; j++) - { - length[j] = table.Rows[j][i].ToString().Trim().Length; - } - lengthByColumn[i] = length.Max(); - } - return CompareToColumnNameLengthAndUpdate(table, lengthByColumn); - } + lengthByColumn[columnIndex] = Math.Max(rowsLengths.Max(), table.Columns[columnIndex].ColumnName.Trim().Length); + } - private static Dictionary CompareToColumnNameLengthAndUpdate(DataTable table, - IReadOnlyDictionary lenghtByColumnDictionary) - { - var dictionary = new Dictionary(); - for (var i = 0; i < table.Columns.Count; i++) - { - var columnNameLength = table.Columns[i].ColumnName.Trim().Length; - dictionary[i] = columnNameLength > lenghtByColumnDictionary[i] - ? columnNameLength - : lenghtByColumnDictionary[i]; - } - return dictionary; - } + return lengthByColumn; + } - private static string PadWithSpaceAndSeperator(string value, int totalColumnLength) - { - var remaningSpace = value.Length < totalColumnLength - ? totalColumnLength - value.Length - : value.Length - totalColumnLength; - var spaces = string.Join("", Enumerable.Repeat(" ", remaningSpace).ToArray()); - return value + spaces + " | "; - } - } -} + private static void AppendColumns(DataTable table, StringBuilder tableBuilder, IReadOnlyDictionary lengthByColumn) + { + for (var columnIndex = 0; columnIndex < table.Columns.Count; columnIndex++) + { + var columName = table.Columns[columnIndex].ColumnName.Trim(); + var paddedColumNames = AlignValueAndAddSeparator(ToTitleCase(columName), lengthByColumn[columnIndex]); + tableBuilder.Append(paddedColumNames); + } + + tableBuilder.AppendLine(); + tableBuilder.AppendLine(string.Join("", Enumerable.Repeat(HEADER_SEPARATOR, tableBuilder.ToString().Length - 3).ToArray())); + } + + private static string ToTitleCase(string columnName) + { + return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(columnName.Replace("_", " ")); + } + + private static void AppendRows(DataTable table, StringBuilder tableBuilder, IReadOnlyDictionary lengthByColumn) + { + for (var rowIndex = 0; rowIndex < table.Rows.Count; rowIndex++) + { + var rowBuilder = new StringBuilder(); + + for (var columnIndex = 0; columnIndex < table.Columns.Count; columnIndex++) + { + rowBuilder.Append(AlignValueAndAddSeparator(table.Rows[rowIndex][columnIndex].ToString()?.Trim(), lengthByColumn[columnIndex])); + } + + tableBuilder.AppendLine(rowBuilder.ToString()); + } + } + + private static string AlignValueAndAddSeparator(string? value, int columnLength) + { + var spaces = string.Empty; + + if (value != null) + { + var remainingSpace = value.Length < columnLength ? columnLength - value.Length : value.Length - columnLength; + spaces = string.Join("", Enumerable.Repeat(ALIGN_CHAR, remainingSpace).ToArray()); + } + + return value + spaces + COLUMN_SEPARATOR; + } + } +} \ No newline at end of file From 1180c6db43a09257ae6ec1eaa65f78a4edd3ef81 Mon Sep 17 00:00:00 2001 From: Artem Yurchenko Date: Mon, 11 Apr 2022 21:23:18 +0200 Subject: [PATCH 2/3] Counting column length was reimplemented to handle table without entities; magic value when applying header separators was explained --- AsciiTableGenerator.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/AsciiTableGenerator.cs b/AsciiTableGenerator.cs index 3de60f4..73d6553 100644 --- a/AsciiTableGenerator.cs +++ b/AsciiTableGenerator.cs @@ -9,6 +9,7 @@ public static class AsciiTableGenerator private const string COLUMN_SEPARATOR = " | "; private const string ALIGN_CHAR = " "; private const string HEADER_SEPARATOR = "-"; + private const int SKIP_HEADER_SEPARATORS = 2; public static StringBuilder CreateAsciiTableFromDataTable(DataTable table) { @@ -33,7 +34,14 @@ private static Dictionary GetLengthByColumn(DataTable table) rowsLengths[rowIndex] = table.Rows[rowIndex][columnIndex].ToString()?.Trim().Length ?? 0; } - lengthByColumn[columnIndex] = Math.Max(rowsLengths.Max(), table.Columns[columnIndex].ColumnName.Trim().Length); + if (rowsLengths.Length == 0) + { + lengthByColumn[columnIndex] = table.Columns[columnIndex].ColumnName.Trim().Length; + } + else + { + lengthByColumn[columnIndex] = Math.Max(rowsLengths.Max(), table.Columns[columnIndex].ColumnName.Trim().Length); + } } return lengthByColumn; @@ -49,7 +57,8 @@ private static void AppendColumns(DataTable table, StringBuilder tableBuilder, I } tableBuilder.AppendLine(); - tableBuilder.AppendLine(string.Join("", Enumerable.Repeat(HEADER_SEPARATOR, tableBuilder.ToString().Length - 3).ToArray())); + // Skipping separators is needed because tableBuilder.Lenght contains also invisible characters like \n. 11.04.2022. Artem Yurchenko + tableBuilder.AppendLine(string.Join("", Enumerable.Repeat(HEADER_SEPARATOR, tableBuilder.Length - SKIP_HEADER_SEPARATORS).ToArray())); } private static string ToTitleCase(string columnName) From 0ec1ad727d05c6609b4f4e00ea5a9852771be5b1 Mon Sep 17 00:00:00 2001 From: Artem Yurchenko Date: Mon, 11 Apr 2022 21:34:48 +0200 Subject: [PATCH 3/3] AsciiTableGeneratorTests were added (valid, tested in another solution) --- AsciiTableGeneratorTests.cs | 45 +++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 AsciiTableGeneratorTests.cs diff --git a/AsciiTableGeneratorTests.cs b/AsciiTableGeneratorTests.cs new file mode 100644 index 0000000..11f7b5c --- /dev/null +++ b/AsciiTableGeneratorTests.cs @@ -0,0 +1,45 @@ +using System.Data; + +namespace AsciiTableGenerators; + +public class AsciiTableGeneratorTests +{ + // NUnit was used. 11.04.2022. Artem Yurchenko + + // [Test] + // public void CreateTableWithHeadersOnly_GeneratorReturnsExpectedString_True () + // { + // DataTable table = new(); + // table.Columns.Add("Column1"); + // table.Columns.Add("Column2"); + // + // string tableString = AsciiTableGenerator.CreateAsciiTableFromDataTable(table).ToString(); + // + // Assert.AreEqual("Column1 | Column2 | \n-------------------\n", tableString); + // } + // + // [Test] + // public void CreateSimpleTable_GeneratorReturnsExpectedString_True () + // { + // DataTable table = new(); + // table.Columns.Add("Column1"); + // table.Columns.Add("Column2"); + // table.Rows.Add("Row1", "Row2"); + // + // string tableString = AsciiTableGenerator.CreateAsciiTableFromDataTable(table).ToString(); + // + // Assert.AreEqual("Column1 | Column2 | \n-------------------\nRow1 | Row2 | \n", tableString); + // } + // + // [Test] + // public void CreateTableWithRowBiggerThanColumn_GeneratorReturnsExpectedString_True () + // { + // DataTable table = new(); + // table.Columns.Add("Column1"); + // table.Rows.Add("Column1Bigger"); + // + // string tableString = AsciiTableGenerator.CreateAsciiTableFromDataTable(table).ToString(); + // + // Assert.AreEqual("Column1 | \n---------------\nColumn1Bigger | \n", tableString); + // } +} \ No newline at end of file