Skip to content

Instantly share code, notes, and snippets.

@YuukanOO
Last active October 17, 2018 15:33
Show Gist options
  • Save YuukanOO/45258d0cadc27d99337aa6fe51ce2d14 to your computer and use it in GitHub Desktop.
Save YuukanOO/45258d0cadc27d99337aa6fe51ce2d14 to your computer and use it in GitHub Desktop.
Ascii table parser in C#
class Program
{
static void Main(string[] args)
{
using (var package = new ExcelPackage(File.Create(@"C:\Temp\test.xlsx")))
{
var sheet = package.Workbook.Worksheets.Add("Sandbox");
var parser = new TableParser(1, 1);
parser.InsertRow += (row) => sheet.InsertRow(row, 1);
parser.SetCell += (row, col, tag) => sheet.Cells[row, col].Value = tag;
parser.MergeCell += (fromRow, fromCol, toRow, toCol) => sheet.Cells[fromRow, fromCol, toRow, toCol].Merge = true;
parser.Parse(@"
|-------------------------------|---------------|
| 1 | 11 |
|---------------|---------------|---------------|
| 2 | 3 | 12 |
|---------------|---------------|---------------|
| 4 | 5 | 13 |
| |---------------| |
| | 6 | |
|---------------|---------------| |
| 7 | 8 | |
|---------------| | |
| 9 | | |
| |---------------| |
| | 10 | |
|---------------|---------------|---------------|");
parser.Seek(parser.CurrentRow + 1, 1);
parser.Parse(@"
|------------------------------------------------------------------------------------|
| a | | |
| |----------------|----------------|----------------|----------------|
| | b | c | d | e |
|----------------|----------------|----------------|----------------|----------------|
");
package.Save();
}
}
}
public sealed class TableParser
{
class Range
{
public int FromRow;
public int ToRow;
public int FromCol;
public int ToCol;
}
#region Delegates
public delegate void InsertRowDelegate(int row);
public delegate void SetCellDelegate(int row, int col, string section);
public delegate void MergeCellDelegate(int fromRow, int fromCol, int toRow, int toCol);
#endregion
#region Events
public event InsertRowDelegate InsertRow;
public event SetCellDelegate SetCell;
public event MergeCellDelegate MergeCell;
#endregion
public int CurrentRow { get; private set; }
private int _rowOffset;
private int _colOffset;
private Dictionary<int, Range> _cellsSpan;
private int[] _columnsDefinitions;
private readonly Regex _colDelimiterRegex = new Regex("([|])", RegexOptions.Compiled);
private readonly Regex _rowDelimiterRegex = new Regex("([-]+)", RegexOptions.Compiled);
private readonly Regex _rowContentRegex = new Regex("([^|]+)", RegexOptions.Compiled);
public TableParser(int rowOffset = 0, int colOffset = 0)
{
_rowOffset = rowOffset;
_colOffset = colOffset;
}
public void Seek(int row, int col)
{
_rowOffset = row;
_colOffset = col;
}
private int FindCol(int index)
{
for (var idx = 0; idx <= _columnsDefinitions.Length; ++idx)
{
if (index <= _columnsDefinitions[idx] || _columnsDefinitions[idx] >= index)
{
return idx;
}
}
return 0;
}
public void Parse(string ascii)
{
CurrentRow = 0;
_columnsDefinitions = new int[0];
_cellsSpan = new Dictionary<int, Range>();
var lines = ascii.Split(new string[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var matches = _colDelimiterRegex.Matches(line);
if (matches.Count > _columnsDefinitions.Length)
{
_columnsDefinitions = matches.Skip(1).Select(o => o.Index).ToArray();
}
}
foreach (var line in lines)
{
var matches = _rowDelimiterRegex.Matches(line);
if (matches.Any())
{
foreach (Match match in matches)
{
var colToClose = FindCol(match.Index);
if (_cellsSpan.TryGetValue(colToClose, out Range range))
{
if (range.FromRow != range.ToRow || range.FromCol != range.ToCol)
{
MergeCell?.Invoke(
_rowOffset + range.FromRow,
_colOffset + range.FromCol,
_rowOffset + range.ToRow,
_colOffset + range.ToCol);
}
_cellsSpan.Remove(colToClose);
}
}
continue;
}
InsertRow?.Invoke(_rowOffset + CurrentRow);
foreach (Match match in _rowContentRegex.Matches(line))
{
var curStartCol = FindCol(match.Index);
var curEndCol = FindCol(match.Index + match.Length);
if (!_cellsSpan.ContainsKey(curStartCol))
{
_cellsSpan[curStartCol] = new Range
{
FromRow = CurrentRow,
FromCol = curStartCol,
ToCol = curEndCol,
};
SetCell?.Invoke(_rowOffset + CurrentRow, _colOffset + curStartCol, match.Value.Trim());
}
_cellsSpan[curStartCol].ToRow = CurrentRow;
}
++CurrentRow;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment