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++17 port: split delimiter-separated rows and render a padded GFM table, ported from src/lib/markdown-table.ts.
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
enum class Align { None, Left, Center, Right };
// splitLine: literal-delimiter split (',', '\t', ';'), each cell trimmed.
std::vector<std::string> splitLine(const std::string& line, char delim) {
std::vector<std::string> cells;
size_t start = 0;
for (size_t i = 0; i <= line.size(); i++) {
if (i == line.size() || line[i] == delim) {
size_t b = start, e = i;
while (b < e && isspace(static_cast<unsigned char>(line[b]))) b++;
while (e > b && isspace(static_cast<unsigned char>(line[e - 1]))) e--;
cells.push_back(line.substr(b, e - b));
start = i + 1;
}
}
return cells;
}
// parseTable: non-empty (post-trim) lines, each split by the delimiter.
std::vector<std::vector<std::string>> parseTable(const std::string& input, char delim) {
std::vector<std::vector<std::string>> rows;
std::string line;
std::istringstream stream(input);
while (std::getline(stream, line)) {
if (!line.empty() && line.back() == '\r') line.pop_back();
size_t b = line.find_first_not_of(" \t");
if (b == std::string::npos) continue; // blank line
size_t e = line.find_last_not_of(" \t");
rows.push_back(splitLine(line.substr(b, e - b + 1), delim));
}
return rows;
}
// escapeCell: newlines collapse to spaces, a literal '|' renders as '\|'.
std::string escapeCell(const std::string& cell) {
std::string out;
for (char c : cell) {
if (c == '\n' || c == '\r') out += ' ';
else {
if (c == '|') out += '\\';
out += c;
}
}
return out;
}
// pad: fill to width honoring right/center/left alignment.
std::string pad(const std::string& cell, size_t width, Align a) {
size_t diff = width > cell.size() ? width - cell.size() : 0;
if (diff == 0) return cell;
if (a == Align::Right) return std::string(diff, ' ') + cell;
if (a == Align::Center) {
size_t l = diff / 2;
return std::string(l, ' ') + cell + std::string(diff - l, ' ');
}
return cell + std::string(diff, ' '); // Left, None -> left-aligned
}
// sepCell: ---, :--, --:, :-: — the alignment separator, min width 3.
std::string sepCell(Align a, size_t width) {
size_t w = std::max<size_t>(3, width);
switch (a) {
case Align::Center: return ":" + std::string(w - 2, '-') + ":";
case Align::Right: return std::string(w - 1, '-') + ":";
case Align::Left: return ":" + std::string(w - 1, '-');
default: return std::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.
std::string toMarkdown(std::vector<std::vector<std::string>> rows, bool header,
std::vector<Align> aligns) {
if (rows.empty()) return "";
size_t cols = 0;
for (auto& r : rows) {
for (auto& c : r) c = escapeCell(c);
cols = std::max(cols, r.size());
r.resize(cols, "");
}
std::vector<size_t> widths(cols, 3);
std::vector<Align> align(cols, Align::None);
for (size_t c = 0; c < cols; c++) {
if (c < aligns.size()) align[c] = aligns[c];
for (const auto& r : rows) widths[c] = std::max(widths[c], r[c].size());
}
auto line = [&](const std::vector<std::string>& cells) {
std::string out = "| ";
for (size_t c = 0; c < cols; c++) {
if (c > 0) out += " | ";
out += pad(cells[c], widths[c], align[c]);
}
return out + " |";
};
std::string separator = "| ";
for (size_t c = 0; c < cols; c++) {
if (c > 0) separator += " | ";
separator += sepCell(align[c], widths[c]);
}
separator += " |";
std::vector<std::string> out;
out.push_back(header ? line(rows[0]) : line(std::vector<std::string>(cols, "")));
out.push_back(separator);
for (size_t i = header ? 1 : 0; i < rows.size(); i++) out.push_back(line(rows[i]));
std::string result;
for (size_t i = 0; i < out.size(); i++) {
if (i > 0) result += '\n';
result += out[i];
}
return result;
}
int main() {
// Demo: a CSV-ish grid with a literal pipe in one cell (escaped on output).
std::vector<std::vector<std::string>> rows =
parseTable("Name,Price,Qty\nWire | cable,2 m,1\nLED,3 mm,25", ',');
std::cout << toMarkdown(rows, true, {Align::None, Align::Right, Align::Center}) << "\n";
}
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 →