Commit dc45e413 authored by hydrargyrum's avatar hydrargyrum

realign-text-table: tool to rebuild plain-text table

- takes a malformed ASCII-drawn table as stdin or file, for example:
    +-----+-----+
    | foo | bar |
    +-----+-----+
    | a long cell | short |
    | x | longer cell ? |
    +--+--+

- outputs a well-formed table:
    +-------------+---------------+
    |     foo     |      bar      |
    +-------------+---------------+
    | a long cell |     short     |
    |      x      | longer cell ? |
    +-------------+---------------+
parent b376c8f4
......@@ -33,6 +33,7 @@ This repository hosts various small personal tools.
* r2w_plugins: 2 rest2web plugins
* radiodump: circular buffer and dump to file
* random-line: take a random line from stdin
* realign-text-table: takes a malformed ASCII-drawn table and redraw borders properly
* redmine2ical: convert Redmine’s timesheet to iCalendar format
* set-cachedir: basic tool to create CACHEDIR.TAG files (prevent a folder from being backed up)
* stickimage: display an image always-on-top like a sticky note
......
#!/usr/bin/env python3
# license: Do What the Fuck You Want to Public License v2 [http://www.wtfpl.net/]
# - takes a malformed ASCII-drawn table as stdin or file, for example:
# +-----+-----+
# | foo | bar |
# +-----+-----+
# | a long cell | short |
# | x | longer cell ? |
# +--+--+
#
# - outputs a well-formed table:
# +-------------+---------------+
# | foo | bar |
# +-------------+---------------+
# | a long cell | short |
# | x | longer cell ? |
# +-------------+---------------+
from fileinput import input
import re
from prettytable import PrettyTable
replacements = {
'─=': '-',
'│': '|',
'┘┐└┌├┬┼┴┤': '+',
}
box_chars = ''.join(replacements.keys()) + ''.join(replacements.values())
box_chars_regex = re.compile(r'[%s\s]+' % re.escape(box_chars))
table_regex = re.compile(
r"""
^
\s*(
[-─=]+
| [+|│┌└├] [+-┬┼┴─\s]* [+|│┤┘┐]
| [|│] .* [|│]
)\s*
$
""",
re.X
)
def dump_table(rows):
if not rows:
return
table = PrettyTable()
header, rows = rows[0], rows[1:]
assert not header[0]
assert not header[-1]
table.field_names = header[1:-1]
for row in rows:
assert not row[0]
assert not row[-1]
table.add_row(row[1:-1])
print(table)
rows = []
for line in input():
if not table_regex.fullmatch(line):
dump_table(rows)
rows = []
print(line, end='')
continue
if box_chars_regex.fullmatch(line):
continue
line = line.rstrip()
row = [el.strip() for el in re.split('[│|]', line)]
rows.append(row)
dump_table(rows)
#!/usr/bin/env python3
# license: Do What the Fuck You Want to Public License v2 [http://www.wtfpl.net/]
from pathlib import Path
import subprocess
tests = """
| foo | bar |
| long text | other |
| x | y |
+---+--+
| foo | bar |
+-------+--+
| a | b |
+-------+--+
| c | d |
+-------+--+
┌─────┬─────┐
│ foo │ bar │
├─────┼─────┤
│ a │ b │
│ c │ d │
└─────┴─────┘
--------
| 1 | 2 | 3 |
-----------------------
| 4 | 5 | 6 |
========
| 7 | 8 | nine |
""".strip().split('\n\n')
expecteds = """
+-----------+-------+
| foo | bar |
+-----------+-------+
| long text | other |
| x | y |
+-----------+-------+
+-----+-----+
| foo | bar |
+-----+-----+
| a | b |
| c | d |
+-----+-----+
+-----+-----+
| foo | bar |
+-----+-----+
| a | b |
| c | d |
+-----+-----+
+---+---+------+
| 1 | 2 | 3 |
+---+---+------+
| 4 | 5 | 6 |
| 7 | 8 | nine |
+---+---+------+
""".strip().split('\n\n')
def run_one(test, expected):
output = subprocess.check_output(
[Path(__file__).resolve().with_name('realign-text-table')],
input=test, encoding='utf-8'
).rstrip('\n')
expected = expected.rstrip('\n')
assert output == expected
def test_basic():
assert len(tests) == len(expecteds)
for test, expected in zip(tests, expecteds):
run_one(test, expected)
run_one(expected, expected)
doc_test = """
a document
something
this is a table:
| foo | bar |
| long text | other |
| x | y |
end
"""
doc_expected = """
a document
something
this is a table:
+-----------+-------+
| foo | bar |
+-----------+-------+
| long text | other |
| x | y |
+-----------+-------+
end
"""
def test_embedded():
run_one(doc_test, doc_expected)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment