Skip to content

Markdown Table Generator — C# source

Turn pipe, CSV, tab, semicolon, or space-separated data into a clean GitHub-Flavored Markdown table. Auto-detects the delimiter, pads columns, escapes pipes, and supports per-column alignment - all in your browser.

This is the C# implementation — the same logic the interactive tool runs, in a shareable, citable form.

// markdown-table — C# (.NET 8) port: split delimiter-separated rows and render a padded GFM table, ported from src/lib/markdown-table.ts.

#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;

enum Align { None, Left, Center, Right }

static class MarkdownTable
{
    // escapeCell: newlines collapse to spaces, a literal '|' renders as '\|'.
    static string EscapeCell(string cell) =>
        cell.Replace("\r\n", "\n").Replace("\n", " ").Replace("|", "\\|");

    // splitLine: literal-delimiter split (',', '\t', ';'), each cell trimmed.
    static string[] SplitLine(string line, char delim) =>
        line.Split(delim).Select(c => c.Trim()).ToArray();

    // parseTable: non-empty lines, each split by the delimiter.
    public static string[][] ParseTable(string input, char delim) =>
        input.Split(new[] { "\r\n", "\n", "\r" }, StringSplitOptions.None)
             .Select(l => l.Trim())
             .Where(l => l.Length > 0)
             .Select(l => SplitLine(l, delim))
             .ToArray();

    // pad: fill to width honoring right/center/left alignment.
    static string Pad(string cell, int width, Align align)
    {
        int diff = width - cell.Length;
        if (diff <= 0) return cell;
        return align switch
        {
            Align.Right => new string(' ', diff) + cell,
            Align.Center => new string(' ', diff / 2) + cell + new string(' ', diff - diff / 2),
            _ => cell + new string(' ', diff), // Left, None -> left-aligned
        };
    }

    // sepCell: ---, :--, --:, :-: — the alignment separator, min width 3.
    static string SepCell(Align align, int width)
    {
        int w = Math.Max(3, width);
        return align switch
        {
            Align.Center => ":" + new string('-', w - 2) + ":",
            Align.Right => new string('-', w - 1) + ":",
            Align.Left => ":" + new string('-', w - 1),
            _ => new string('-', w),
        };
    }

    // toMarkdown: pad every column to its widest (escaped) cell and lay rows
    // out as '| a | b |', with the separator row under the header row.
    public static string ToMarkdown(string[][] rows, bool header = true, Align[]? aligns = null)
    {
        if (rows.Length == 0) return "";
        int cols = rows.Max(r => r.Length);
        string[][] grid = rows.Select(r =>
        {
            var cells = r.Select(EscapeCell).ToList();
            while (cells.Count < cols) cells.Add("");
            return cells.ToArray();
        }).ToArray();
        Align[] align = Enumerable.Range(0, cols)
            .Select(i => aligns != null && i < aligns.Length ? aligns[i] : Align.None).ToArray();
        int[] widths = Enumerable.Range(0, cols)
            .Select(c => Math.Max(3, grid.Max(r => r[c].Length))).ToArray();

        string Line(string[] cells) =>
            "| " + string.Join(" | ", cells.Select((c, i) => Pad(c, widths[i], align[i]))) + " |";
        string separator = "| " + string.Join(" | ", align.Select((a, i) => SepCell(a, widths[i]))) + " |";

        string[] head = header ? grid[0] : Enumerable.Repeat("", cols).ToArray();
        IEnumerable<string[]> data = header ? grid.Skip(1) : grid;
        return string.Join("\n", new[] { Line(head), separator }.Concat(data.Select(Line)));
    }
}

class Program
{
    static void Main()
    {
        // Demo: a CSV-ish grid with a literal pipe in one cell (escaped on output).
        string[][] rows = MarkdownTable.ParseTable("Name,Price,Qty\nWire | cable,2 m,1\nLED,3 mm,25", ',');
        Console.WriteLine(MarkdownTable.ToMarkdown(rows,
            aligns: new[] { Align.None, Align.Right, Align.Center }));
    }
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →