Last active
May 19, 2022 05:25
-
-
Save LuviKunG/bf21d25826de824b5009cd580e904432 to your computer and use it in GitHub Desktop.
CSV Reader and Table Data. (by LuviKunG)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.IO; | |
using System.Text; | |
/* | |
CSV Reader (with parser). | |
Created by @LuviKunG | |
https://github.com/LuviKunG | |
https://gist.github.com/LuviKunG | |
*/ | |
namespace Serialization | |
{ | |
/// <summary> | |
/// CSV Reader static class that use to parse any text or file into <see cref="TableData"/> class. | |
/// </summary> | |
public static class CSVReader | |
{ | |
/// <summary> | |
/// Parse from file. | |
/// </summary> | |
/// <param name="path">Uri file path.</param> | |
/// <returns><see cref="TableData"/> class that contains value in the table.</returns> | |
public static TableData ParseFromFile(string path) | |
{ | |
string text = File.ReadAllText(path); | |
return Parse(text); | |
} | |
/// <summary> | |
/// Parse from raw string text. | |
/// </summary> | |
/// <param name="text">Raw string text.</param> | |
/// <returns><see cref="TableData"/> class that contains value in the table.</returns> | |
public static TableData Parse(string text) | |
{ | |
// Cache the longest row while parsing for easy to assign to the table. | |
int longestRow = 0; | |
// Create list as column of every row. | |
List<List<string>> list = new List<List<string>>(); | |
// Create current row. | |
List<string> row = new List<string>(); | |
// Using string builder for efficiency. | |
StringBuilder sb = new StringBuilder(); | |
// Hold flag that is in quote mode or not. | |
bool quote = false; | |
// Use for loop for every character because needs to validate every char algorithm. | |
for (int i = 0; i < text.Length; ++i) | |
{ | |
// If quotes. | |
if (text[i] == '\"') | |
{ | |
// But if next is quote, so put qoute. | |
if (i + 1 < text.Length && text[i + 1] == '\"') | |
{ | |
sb.Append('\"'); | |
++i; | |
} | |
// If not, toggle quote mode. | |
else | |
quote = !quote; | |
continue; | |
} | |
// If isn't in quote mode, will do validation. | |
if (!quote) | |
{ | |
// If end of cell. | |
if (text[i] == ',') | |
{ | |
row.Add(sb.ToString()); | |
sb.Clear(); | |
continue; | |
} | |
// If end of rows with check \n\r or \r\n. | |
if ((text[i] == '\n' && i + 1 < text.Length && text[i + 1] == '\r') || (text[i] == '\r' && i + 1 < text.Length && text[i + 1] == '\n')) | |
{ | |
row.Add(sb.ToString()); | |
sb.Clear(); | |
list.Add(row); | |
// Calculate longest row from current active row. | |
longestRow = row.Count > longestRow ? row.Count : longestRow; | |
row = new List<string>(); | |
++i; | |
continue; | |
} | |
// If end of rows with check \n or \r. | |
if (text[i] == '\n' || text[i] == '\r') | |
{ | |
row.Add(sb.ToString()); | |
sb.Clear(); | |
list.Add(row); | |
// Calculate longest row from current active row. | |
longestRow = row.Count > longestRow ? row.Count : longestRow; | |
row = new List<string>(); | |
continue; | |
} | |
} | |
// If nothing need to validate, just append the current character. | |
sb.Append(text[i]); | |
} | |
// Add last value that in string builder to last row. | |
row.Add(sb.ToString()); | |
// Clear string builder char array cache. | |
sb.Clear(); | |
// Add last active row. | |
list.Add(row); | |
// Calculate longest row from current active row. | |
longestRow = row.Count > longestRow ? row.Count : longestRow; | |
// Create table class and put every value in list of columns and row. | |
TableData csvTable = new TableData(longestRow, list.Count); | |
for (int c = 0; c < list.Count; ++c) | |
for (int r = 0; r < list[c].Count; ++r) | |
csvTable[r, c] = list[c][r]; | |
return csvTable; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using System.Text; | |
/* | |
CSV Writer. | |
Created by @LuviKunG | |
https://github.com/LuviKunG | |
https://gist.github.com/LuviKunG | |
*/ | |
namespace Serialization | |
{ | |
/// <summary> | |
/// CSV Writer static class that use to convert any table into <see cref="TableData"/> class. | |
/// </summary> | |
public static class CSVWriter | |
{ | |
private const char CHAR_SPACE = ' '; | |
private const char CHAR_COMMA = ','; | |
private const char CHAR_SINGLE_QUOTE = '\''; | |
private const char CHAR_DOUBLE_QUOTE = '\"'; | |
/// <summary> | |
/// Save content from table to file path. | |
/// </summary> | |
/// <param name="table"><see cref="TableData"/> content.</param> | |
/// <param name="path">Uri path to save.</param> | |
public static void SaveToFile(TableData table, string path) | |
{ | |
string content = Convert(table); | |
File.WriteAllText(path, content); | |
} | |
/// <summary> | |
/// Convert table to CSV content. | |
/// </summary> | |
/// <param name="table"><see cref="TableData"/> content.</param> | |
/// <returns>CSV String content.</returns> | |
public static string Convert(TableData table) | |
{ | |
// Local function. | |
string ParseEscapeCSVString(string str) | |
{ | |
string newStr = str.Trim(); | |
for (int index = 0; index < newStr.Length; ++index) | |
{ | |
if (newStr[index] == CHAR_SINGLE_QUOTE || newStr[index] == CHAR_DOUBLE_QUOTE) | |
{ | |
newStr.Insert(index, CHAR_DOUBLE_QUOTE.ToString()); | |
index += 2; | |
} | |
} | |
return newStr; | |
} | |
StringBuilder sb = new StringBuilder(); | |
for (int c = 0; c < table.Cols; ++c) | |
{ | |
for (int r = 0; r < table.Rows; ++r) | |
{ | |
if (r != 0) | |
sb.Append(CHAR_COMMA); | |
string val = ParseEscapeCSVString(table[r, c]); | |
if (!(val.IndexOf(CHAR_SPACE) < 0)) // Contains space. | |
{ | |
sb.Append(CHAR_DOUBLE_QUOTE); | |
sb.Append(val); | |
sb.Append(CHAR_DOUBLE_QUOTE); | |
} | |
else | |
sb.Append(val); | |
} | |
sb.Append(Environment.NewLine); | |
} | |
return sb.ToString(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Text; | |
/* | |
Table Data. | |
Created by @LuviKunG | |
https://github.com/LuviKunG | |
https://gist.github.com/LuviKunG | |
*/ | |
namespace Serialization | |
{ | |
/// <summary> | |
/// Table class that holding value within columns and rows. | |
/// </summary> | |
public class TableData | |
{ | |
private string[,] table; | |
/// <summary> | |
/// Get value from table. | |
/// </summary> | |
/// <param name="r">Row.</param> | |
/// <param name="c">Column.</param> | |
/// <returns>Value.</returns> | |
public string this[int r, int c] | |
{ | |
get => table[r, c]; | |
set => table[r, c] = value; | |
} | |
/// <summary> | |
/// Row of the table. | |
/// </summary> | |
public int Rows => table.GetLength(0); | |
/// <summary> | |
/// Column of the table. | |
/// </summary> | |
public int Cols => table.GetLength(1); | |
/// <summary> | |
/// Create table data. | |
/// rows and columns must be greater than zero. | |
/// </summary> | |
/// <param name="rows"></param> | |
/// <param name="cols"></param> | |
public TableData(int rows, int cols) | |
{ | |
if (rows < 1 || cols < 1) | |
throw new ArgumentException($"Cannot set {nameof(rows)} or {nameof(cols)} below than one."); | |
table = new string[rows, cols]; | |
} | |
/// <summary> | |
/// Resize the table by rows. | |
/// If new size is less than the old size, any outside value in the table will be lost. | |
/// </summary> | |
/// <param name="amount">Size of row.</param> | |
public void ResizeRow(int amount) | |
{ | |
if (amount < 1) | |
throw new ArgumentException($"Cannot set {nameof(amount)} below than one."); | |
Resize(amount, Cols); | |
} | |
/// <summary> | |
/// Resize the table by columns. | |
/// If new size is less than the old size, any outside value in the table will be lost. | |
/// </summary> | |
/// <param name="amount">Size of column.</param> | |
public void ResizeColumn(int amount) | |
{ | |
if (amount < 1) | |
throw new ArgumentException($"Cannot set {nameof(amount)} below than one."); | |
Resize(Rows, amount); | |
} | |
/// <summary> | |
/// Resize the table. | |
/// If new size is less than the old size, any outside value in the table will be lost. | |
/// </summary> | |
/// <param name="rows">Size of row.</param> | |
/// <param name="cols">Size of column.</param> | |
public void Resize(int rows, int cols) | |
{ | |
if (rows < 1 || cols < 1) | |
throw new ArgumentException($"Cannot set {nameof(rows)} or {nameof(cols)} below than one."); | |
string[,] newTable = new string[rows, cols]; | |
for (int c = 0; c < newTable.GetLength(1) && c < Cols; ++c) | |
for (int r = 0; r < newTable.GetLength(0) && r < Rows; ++r) | |
newTable[r, c] = table[r, c]; | |
table = newTable; | |
} | |
/// <summary> | |
/// To String. | |
/// This will show every value in the table. | |
/// </summary> | |
/// <returns>String value as the table.</returns> | |
public override string ToString() | |
{ | |
return ToString(','); | |
} | |
/// <summary> | |
/// To String. | |
/// This will show every value in the table. | |
/// </summary> | |
/// <param name="separator">Character that used for separator of every row.</param> | |
/// <returns>String value as the table.</returns> | |
public string ToString(char separator) | |
{ | |
StringBuilder sb = new StringBuilder(); | |
for (int c = 0; c < Cols; c++) | |
{ | |
sb.Append('['); | |
for (int r = 0; r < Rows; r++) | |
{ | |
if (r != 0) | |
sb.Append(separator); | |
sb.Append(table[r, c]); | |
} | |
sb.Append(']'); | |
sb.AppendLine(); | |
} | |
return sb.ToString(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment