Car/Assets/Plugin/YogiGameCore/FlexReader/Converter/Extensions.cs

508 lines
19 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
namespace FlexFramework.Excel
{
/// <summary>
/// Extensions
/// </summary>
public static class Extensions
{
/// <summary>
/// Convert cell to target type
/// </summary>
/// <param name="cell">Cell</param>
/// /// <param name="type">Target type</param>
/// <returns>Target instance</returns>
public static object Convert(this Cell cell, Type type)
{
return ValueConverter.Convert(type, cell.Text);
}
/// <summary>
/// Convert cell to target type
/// </summary>
/// <typeparam name="T">Target type</typeparam>
/// <param name="cell">Cell</param>
/// <returns>Target instance</returns>
public static T Convert<T>(this Cell cell)
{
return (T)Convert(cell, typeof(T));
}
/// <summary>
/// Convert row to object instance
/// </summary>
/// <typeparam name="T">Target type</typeparam>
/// <param name="row">Row</param>
/// <param name="generator">Generator</param>
/// <returns>Object instance</returns>
public static T Convert<T>(this Row row, IGenerator<T> generator) where T : new()
{
return (T)generator.Instantiate(row);
}
/// <summary>
/// Convert row to object instance
/// </summary>
/// <typeparam name="T">Target type</typeparam>
/// <param name="row">Row</param>
/// <param name="expression">Mapping expression</param>
/// <returns>Object instance</returns>
public static T Convert<T>(this Row row, string expression) where T : new()
{
return Convert(row, new Mapper<T>().Map(expression));
}
/// <summary>
/// Convert row to object instance
/// </summary>
/// <typeparam name="T">Target type</typeparam>
/// <param name="row">Row</param>
/// <param name="cols">Mapping provider</param>
/// <returns>Object instance</returns>
public static T Convert<T>(this Row row, IEnumerable<Cell> cols) where T : new()
{
return Convert(row, new Mapper<T>().Map(cols));
}
/// <summary>
/// Convert row to object instance
/// </summary>
/// <param name="row">Row</param>
/// <param name="type">Target type</param>
/// <param name="expression">Mapping expression</param>
/// <returns>Object instance</returns>
public static object Convert(this Row row, Type type, string expression)
{
return Convert(row, new Mapper(type).Map(expression));
}
/// <summary>
/// Convert row to object instance
/// </summary>
/// <param name="row">Row</param>
/// <param name="type">Target type</param>
/// <param name="cols">Mapping provider</param>
/// <returns>Object instance</returns>
public static object Convert(this Row row, Type type, IEnumerable<Cell> cols)
{
return Convert(row, new Mapper(type).Map(cols));
}
/// <summary>
/// Convert row to object instance
/// </summary>
/// <param name="row">Row</param>
/// <param name="generator">Generator</param>
/// <returns>Object instance</returns>
public static object Convert(this Row row, IGenerator generator)
{
return generator.Instantiate(row);
}
/// <summary>
/// Convert table to target enumerable
/// </summary>
/// <typeparam name="T">Target type</typeparam>
/// <param name="table">Table</param>
/// <returns>Target enumerable</returns>
public static IEnumerable<T> Convert<T>(this Table table) where T : new()
{
var mapper = new TableMapper<T>();
mapper.Extract();
return Convert<T>(table, mapper);
}
/// <summary>
/// Convert table to target enumerable
/// </summary>
/// <param name="table">Table</param>
/// <param name="type">Target type</param>
/// <returns>Target enumerable</returns>
public static IEnumerable<object> Convert(this Table table, Type type)
{
var mapper = new TableMapper(type);
mapper.Extract();
return Convert(table, mapper);
}
/// <summary>
/// Convert table to target enumerable
/// </summary>
/// <typeparam name="T">Target type</typeparam>
/// <param name="table">Table</param>
/// <param name="generator">Generator</param>
/// <returns>Target enumerable</returns>
public static IEnumerable<T> Convert<T>(this Table table, ITableGenerator<T> generator) where T : new()
{
return generator.Instantiate(table);
}
/// <summary>
/// Convert table to target enumerable
/// </summary>
/// <typeparam name="T">Target type</typeparam>
/// <param name="table">Table</param>
/// <param name="row">One-based mapping provider row index</param>
/// <returns>Target enumerable</returns>
public static IEnumerable<T> Convert<T>(this Table table, int row) where T : new()
{
if (row < 1)
{
throw new ArgumentException("One-based row index must be greater than 0");
}
ITableGenerator<T> generator = new TableMapper<T>().Map(table[row - 1]).Exclude(row);
return generator.Instantiate(table);
}
/// <summary>
/// Convert table to target enumerable
/// </summary>
/// <typeparam name="T">Target type</typeparam>
/// <param name="table">Table</param>
/// <param name="expression">Mapping expression</param>
/// <param name="exclude">One-based row indices to exclude</param>
/// <returns>Target enumerable</returns>
public static IEnumerable<T> Convert<T>(this Table table, string expression, params int[] exclude) where T : new()
{
var generator = new TableMapper<T>().Map(expression);
if (exclude != null && exclude.Length > 0)
generator.Exclude(exclude);
return Convert(table, generator);
}
/// <summary>
/// Convert table to target enumerable
/// </summary>
/// <param name="table">Table</param>
/// <param name="type">Target type</param>
/// <param name="expression">Mapping expression</param>
/// <param name="exclude">One-based row indices to exclude</param>
/// <returns>Target enumerable</returns>
public static IEnumerable<object> Convert(this Table table, Type type, string expression, params int[] exclude)
{
var generator = new TableMapper(type).Map(expression);
if (exclude != null && exclude.Length > 0)
generator.Exclude(exclude);
return Convert(table, generator);
}
/// <summary>
/// Convert table to target enumerable
/// </summary>
/// <param name="table">Table</param>
/// <param name="generator">Generator</param>
/// <returns>Target enumerable</returns>
public static IEnumerable<object> Convert(this Table table, ITableGenerator generator)
{
return generator.Instantiate(table);
}
/// <summary>
/// Convert table to target enumerable
/// </summary>
/// <param name="table">Table</param>
/// <param name="type">Target type</param>
/// <param name="row">One-based mapping provider row index</param>
/// <returns>Target enumerable</returns>
public static IEnumerable<object> Convert(this Table table, Type type, int row)
{
if (row < 1)
{
throw new ArgumentException("One-based row index must be greater than 0");
}
ITableGenerator generator = new TableMapper(type).Map(table[row - 1]).Exclude(row);
return generator.Instantiate(table);
}
/// <summary>
/// Dump row data to string
/// </summary>
/// <param name="row">Row</param>
/// <param name="delimiter">Column delimiter</param>
/// <param name="enclose">Column escaping enclose</param>
/// <returns>Plain text</returns>
public static string Dump(this Row row, char delimiter, char enclose)
{
return row.Cells.Select(c => Dump(c, delimiter, enclose)).Aggregate(string.Empty, (a, b) => string.IsNullOrEmpty(a) ? b : a + delimiter + b);
}
/// <summary>
/// Dump row data to string using default delimiter and escaping enclose characters
/// </summary>
/// <param name="row">Row</param>
/// <returns>Plain text</returns>
public static string Dump(this Row row)
{
return Dump(row, Document.Delimiter, Document.Enclose);
}
/// <summary>
/// Dump cell data to string
/// </summary>
/// <remarks>
/// This will enclose delimiter and enclose characters
/// </remarks>
/// <param name="cell">Cell</param>
/// <param name="delimiter">Column delimiter</param>
/// <param name="enclose">Column escaping enclose</param>
/// <returns>Plain text</returns>
public static string Dump(this Cell cell, char delimiter, char enclose)
{
var value = cell.Text;
if (string.IsNullOrEmpty(value))
return string.Empty;
if (value.Contains(enclose) || value.Contains(delimiter))
{
return enclose + value.Replace(enclose.ToString(), enclose.ToString() + enclose) + enclose;
}
return value;
}
/// <summary>
/// Dump cell data to string using default delimiter and escaping enclose characters
/// </summary>
/// <param name="cell">Cell</param>
/// <returns>Plain text</returns>
public static string Dump(this Cell cell)
{
return Dump(cell, Document.Delimiter, Document.Enclose);
}
/// <summary>
/// Dump table data to string
/// </summary>
/// <param name="delimiter">Column delimiter</param>
/// <param name="enclose">Column escaping enclose</param>
/// <returns>Plain text</returns>
public static string Dump(this Table table, char delimiter, char enclose)
{
return table.Select(r => Dump(r, delimiter, enclose)).Aggregate(string.Empty, (a, b) => string.IsNullOrEmpty(a) ? b : a + Environment.NewLine + b);
}
/// <summary>
/// Dump table data to string using default delimiter and escaping enclose characters
/// </summary>
/// <param name="table">Table</param>
/// <returns>Plain text</returns>
public static string Dump(this Table table)
{
return Dump(table, Document.Delimiter, Document.Enclose);
}
/// <summary>
/// Select cell by address formula
/// </summary>
/// <param name="row">Row</param>
/// <param name="address">Address formula(e.g. A1, C20)</param>
/// <returns>Cell or null</returns>
/// <exception cref="FormatException"/>
public static Cell Select(this Row row, string address)
{
if (!Address.IsValid(address))
throw new FormatException();
var ad = new Address(address);
return row.FirstOrDefault(cell => cell.Address == ad);
}
/// <summary>
/// Select cells by range formula
/// </summary>
/// <param name="row">Row</param>
/// <param name="range">Range formula(e.g. A1:A5, B2:C20)</param>
/// <returns>Cells or empty</returns>
/// <exception cref="FormatException"/>
public static IEnumerable<Cell> SelectRange(this Row row, string range)
{
if (!Range.IsValid(range))
throw new FormatException();
return row[new Range(range)];
}
/// <summary>
/// Select cell by address formula
/// </summary>
/// <param name="table">Table</param>
/// <param name="address">Address formula(e.g. A1, C20)</param>
/// <returns>Cell or null</returns>
/// <exception cref="FormatException"/>
public static Cell Select(this Table table, string address)
{
if (!Address.IsValid(address))
throw new FormatException();
var ad = new Address(address);
return table.SelectMany(row => row).FirstOrDefault(cell => cell.Address == ad);
}
/// <summary>
/// Select cells by range formula
/// </summary>
/// <param name="table">Table</param>
/// <param name="range">Range formula(e.g. A1:A5, B2:C20)</param>
/// <returns>Cells or empty</returns>
/// <exception cref="FormatException"/>
public static IEnumerable<Cell> SelectRange(this Table table, string range)
{
if (!Range.IsValid(range))
throw new FormatException();
return table[new Range(range)];
}
/// <summary>
/// Select cell by address formula
/// </summary>
/// <param name="book">WorkBook</param>
/// <param name="path">Address formula(e.g. sheet1!A1, sheet2!C20)</param>
/// <returns>Cell or null</returns>
/// <exception cref="FormatException"/>
public static Cell Select(this WorkBook book, string path)
{
var args = path.Split(new[] { '!' }, StringSplitOptions.RemoveEmptyEntries);
if (args.Length != 2)
throw new FormatException();
var sheet = book.FirstOrDefault(s => s.Name == args[0]);
return sheet == null ? null : Select(sheet, args[1]);
}
/// <summary>
/// Select cells by range formula
/// </summary>
/// <param name="book">WorkBook</param>
/// <param name="path">Range formula(e.g. sheet1!A1:A5, sheet2!B2:C20)</param>
/// <returns>Cells or empty</returns>
/// <exception cref="FormatException"/>
public static IEnumerable<Cell> SelectRange(this WorkBook book, string path)
{
var args = path.Split(new[] { '!' }, StringSplitOptions.RemoveEmptyEntries);
if (args.Length != 2)
throw new FormatException();
var sheet = book.FirstOrDefault(s => s.Name == args[0]);
return sheet == null ? null : SelectRange(sheet, args[1]);
}
/// <summary>
/// Recalculate cells' addresses
/// </summary>
/// <param name="table">Table</param>
public static void Recalculate(this Table table)
{
for (int i = 0; i < table.Count; i++)
{
for (int j = 0; j < table[i].Count; j++)
{
table[i][j].Address = new Address(j + 1, i + 1);
}
}
}
/// <summary>
/// Make a non-rectangular table rectangular
/// </summary>
/// <remarks>
/// This also calls <seealso cref="Recalculate"/>
/// </remarks>
/// <param name="table">Table</param>
/// <returns>Expanded table</returns>
public static Table Expand(this Table table)
{
var expanded = table.DeepClone();
var width = expanded.Max(row => row.Count);
for (int i = 0; i < expanded.Count; i++)
{
var count = width - expanded[i].Count;
while (count > 0)
{
expanded[i].Cells.Add(new Cell());
count--;
}
}
Recalculate(expanded);
return expanded;
}
/// <summary>
/// Remove empty boundary cells from table then remove all empty lines
/// </summary>
/// <remarks>
/// This also calls <seealso cref="Recalculate"/>
/// </remarks>
/// <param name="table">Table</param>
/// <returns>Collapsed table</returns>
public static Table Collapse(this Table table)
{
var collapsed = table.DeepClone();
for (int i = 0; i < collapsed.Count; i++)
{
for (int j = 0; j < collapsed[i].Count; j++)
{
if (!string.IsNullOrEmpty(collapsed[i][j].Text))
break;
collapsed[i].Cells.RemoveAt(j--);
}
for (int j = collapsed[i].Count - 1; j >= 0; j--)
{
if (!string.IsNullOrEmpty(collapsed[i][j].Text))
break;
collapsed[i].Cells.RemoveAt(j);
}
}
for (int i = collapsed.Count - 1; i >= 0; i--)
{
if (collapsed[i].Count == 0)
collapsed.Rows.RemoveAt(i);
}
Recalculate(collapsed);
return collapsed;
}
/// <summary>
/// Rotate table clockwise
/// </summary>
/// <remarks>
/// This also calls <seealso cref="Expand"/>
/// </remarks>
/// <param name="table">Table</param>
/// <returns>Rotated table</returns>
public static Table Rotate(this Table table)
{
var expanded = Expand(table);
if (expanded.Count == 0)
{
return expanded;
}
var height = expanded[0].Count;
if (height == 0)
{
return expanded;
}
var width = expanded.Count;
var rotated = table.DeepClone();
rotated.Rows.Clear();
for (int i = 0; i < height; i++)
{
var row = new Row();
for (int j = width - 1; j >= 0; j--)
{
row.Cells.Add(expanded[j][i]);
}
rotated.Rows.Add(row);
}
Recalculate(rotated);
return rotated;
}
/// <summary>
/// Check if a row is empty(with no cells or all cells' values being null or empty string)
/// </summary>
/// <param name="row">Row</param>
/// <returns>True if empty</returns>
public static bool IsEmpty(this Row row)
{
return row.Count == 0 || row.All(col => string.IsNullOrEmpty(col.Text));
}
}
}