Engineering Journal
Table Formatter
Table Formatter

Seven Parsers, One Interface: How TAFNE Handles Every Table Format

2026-05-11

TLDR

Supporting diverse data formats (HTML, CSV, TSV, Markdown, JSON, ASCII art, SQL INSERT statements) through a single input interface requires combining semantic declaration parsers with pattern-matching heuristic parsers. Dispatching inputs to dedicated normalization functions produces standardized HTML tables without data loss.
Format ClassificationInput Types SupportedStructural Extraction MethodOutput Target
Semantic DeclarativeHTML, JSONDirect DOM / Key-value mappingNormalized <table> string
Heuristic Pattern-MatchingCSV, TSV, ASCII, Markdown, SQLRegex pattern & delimiter scansNormalized <table> string

Normalizing unstructured data requires combining heuristic pattern matching with semantic extraction

Building a table editor that accepts arbitrary pastes requires handling both structured data (like JSON or HTML fragments) and informal text conventions (like Markdown pipe tables or SQL scripts).

We divided our parsing layer into two strategies:

  1. Semantic Parsers: Rely on explicit syntax markup (tags or object keys).
  2. Heuristic Parsers: Infer boundaries using delimiters or string pattern matching.

Dispatching inputs through a centralized switch router normalizes all data into a canonical format

All input strings pass through a centralized dispatcher (parseInput()), converting incoming payloads into standardized HTML table structures:

   PARSER DISPATCH ARCHITECTURE:

[Raw Input String] + [Format Type] │ ▼ ┌────────────────────────────────┐ │ Central Dispatcher │ │ parseInput(text, type) │ └────────────────┬───────────────┘ │ ┌──────────────┬──────────┼──────────┬──────────────┐ ▼ ▼ ▼ ▼ ▼ [HTML Parser] [JSON Parser] [CSV/TSV] [SQL Parser] [Markdown] │ │ │ │ │ │ │ │ │ │ └──────────────┴──────────┼──────────┴──────────────┘ │ ▼ [Normalized HTML <table> String]

Here is the implementation of the centralized switch dispatch logic:

// Centralized multi-format table parsing dispatcher
export function parseInput(rawText, formatType) {
  switch (formatType) {
    case 'html':     return parseHtmlInput(rawText);
    case 'json':     return parseJsonInput(rawText);
    case 'csv':      return parseCsvInput(rawText);
    case 'markdown': return parseMarkdownInput(rawText);
    case 'sql':      return parseSqlInput(rawText);
    case 'ascii':    return parseAsciiInput(rawText);
    default:         return parseTextInput(rawText); // Tab/space fallback
  }
}

// Example SQL parser extracting INSERT queries function parseSqlInput(sqlString) { const insertRegex = /INSERT\s+INTO\s+\S+\s\(([^)]+)\)\sVALUES\s*\(([^)]+)\)/gi; let match; const rows = []; let headers = null;

while ((match = insertRegex.exec(sqlString)) !== null) { if (!headers) { headers = match[1].split(',').map(h => h.trim().replace(/[`"']/g, '')); } const values = match[2].split(',').map(v => v.trim().replace(/^'|'$/g, '')); rows.push(values); } return buildHtmlTableString(headers, rows); }

By decoupling input parsing from the main canvas UI, the editor treats all imported sources as standardized tabular HTML data.

Rule of thumb: Normalize heterogeneous input formats into a canonical HTML representation through a centralized parser dispatcher.
Read this post in the full Engineering Journal →