Table conversion guide
Convert an ASCII table to JSON on the command line
An aligned text table often exposes enough structure to recover records: headers name the columns, while spacing or borders mark their boundaries. jc-rs handles simple fixed-width output and bordered tables whose logical rows span several lines. Arbitrary prose does not provide those guarantees.
By Oleg Sotnikov · Published · Input and output examples checked against both jc-rs ASCII table parsers
Choose by row structure, not border style
jc-rs has two related parsers. Both accept ASCII or Unicode table characters and strip terminal ANSI color sequences. Choose between them based on whether one data row fits on one physical line.
The source already offers JSON
native outputKeep the native schema; no table parser is needed
Simple table: one line becomes one object
The first non-empty row supplies the headers. Spacing in that row establishes column positions; the following rows are read against those positions.
NAME STATUS PORT
api healthy 8080
worker draining 9090jc-rs -p --asciitable < table.txt[
{
"name": "api",
"port": "8080",
"status": "healthy"
},
{
"name": "worker",
"port": "9090",
"status": "draining"
}
]The output is an array, so jq can filter it without returning to column offsets. This example converts the port explicitly because the table parser preserves it as text:
jc-rs --asciitable < table.txt |
jq 'map(select((.port | tonumber) >= 9000))'Multiline table: preserve wrapped cell content
In a pretty table, border rows identify where one logical record ends and the next starts. The multiline parser joins successive physical lines in the same cell with a newline.
+----------+--------+--------------------+
| SERVICE | OWNER | NOTE |
+==========+========+====================+
| api | ops | waiting for |
| | | database migration |
+----------+--------+--------------------+
| worker | data | ready |
+----------+--------+--------------------+jc-rs -p --asciitable-m < multiline-table.txt[
{
"note": "waiting for\ndatabase migration",
"owner": "ops",
"service": "api"
},
{
"note": "ready",
"owner": "data",
"service": "worker"
}
]The multiline parser intentionally accepts “pretty” bordered tables. If it detects a simple or Markdown table, it returns an error and directs you to --asciitable; that prevents ordinary rows from being collapsed together by guesswork.
How headers become JSON keys
Headers are lowercased and normalized toward snake_case. Spaces between words become underscores, punctuation is normalized, and an empty cell becomes null. Multiline header bands are collapsed into combined names.
Service Nameservice_namePORTporttwo header bands: Disk / Useddisk_usedempty data cellnullDo not assume a numeric-looking cell became a JSON number. Inspect the actual result and use jq's tonumber at the point where numeric semantics are required. This also makes conversion failures visible.
“Text to JSON” only works when the text has a schema
A table parser can recover explicit columns. It cannot know whether a sentence, stack trace, paragraph, or casually spaced note contains a name, timestamp, status, or message. Converting arbitrary prose would require domain rules, not a universal parser.
Good table input
A header row, repeatable column positions, and one clear record boundary.
Not enough structure
Wrapped prose, inconsistent labels, or whitespace that changes meaning from line to line.
If the source is delimited, use the CSV parser or TSV parser. If each line is genuinely key/value data, inspect the key/value parser. Pick the grammar the producer actually writes.
When columns land in the wrong field
- 01Capture raw output rather than copying from a rendered web page or proportional font. Character positions are part of the input.
- 02Make the producer use a wide, non-interactive layout when possible. Terminal-width wrapping can turn one record into several unrelated lines.
- 03Check the header first. A header centered differently from its data may establish the wrong boundary even when the rows look aligned to a person.
- 04Use
--asciitable-monly when explicit border rows delimit logical records. Otherwise keep the simple parser. - 05Compare several output versions. If a command changes its layout across systems, prefer that command's dedicated jc-rs parser when one exists.
Choose the most specific parser available
The parser references document each input contract. The Bash and jq guide explains how to carry the resulting rows safely into a larger script.