Text Table
(require text-table) | package: text-table |
License: APACHE2+MIT
To install:
raco pkg install text-table |
See the example in the main submodule of the "main.rkt" file. You can observe the results by running:
racket -l text-table |
; Minimalistic example:
> (print-table '((a b c d e f gggg h) (123 456 77 54 1 5646547987 41 1) (111 22 3333 44 5 6 7 8888)))
┌───┬───┬────┬──┬─┬──────────┬────┬────┐
│a │b │c │d │e│f │gggg│h │
├───┼───┼────┼──┼─┼──────────┼────┼────┤
│123│456│77 │54│1│5646547987│41 │1 │
├───┼───┼────┼──┼─┼──────────┼────┼────┤
│111│22 │3333│44│5│6 │7 │8888│
└───┴───┴────┴──┴─┴──────────┴────┴────┘
; With more bells and whistles
> (print-table '((a b c d e f gggg h) (123 456 77 54 1 5646547987 41 1) (111 22 3333 44 5 6 7 8888)) #:border-style 'double #:framed? #f #:row-sep? #t #:align '(left center right))
a ║ b ║ c║ d║e║ f║gggg║ h
═══╬═══╬════╬══╬═╬══════════╬════╬════
123║456║ 77║54║1║5646547987║ 41║ 1
═══╬═══╬════╬══╬═╬══════════╬════╬════
111║22 ║3333║44║5║ 6║ 7║8888
; Custom border style using border-style-frame/c
> (print-table '((abc abc abc) (abcdef ab abcdef) (a abcdef abc)) #:border-style '("╭─┬╮" "│.││" "├─┼┤" "╰─┴╯") #:align '(center) #:framed? #t #:row-sep? #t)
╭──────┬──────┬──────╮
│.abc..│.abc..│.abc..│
├──────┼──────┼──────┤
│abcdef│..ab..│abcdef│
├──────┼──────┼──────┤
│..a...│abcdef│.abc..│
╰──────┴──────┴──────╯
; Custom border style using border-style2/c
> (print-table '((abc abc abc) (abcdef ab abcdef) (a abcdef abc)) #:border-style '(("<table>" "" "" "") ("<tr><td> " " " " </td><td> " " </td></tr>") ("" "" "" "") ("</table>" "" "" "")) #:framed? #t #:row-sep? #f)
<table>
<tr><td> abc </td><td> abc </td><td> abc </td></tr>
<tr><td> abcdef </td><td> ab </td><td> abcdef </td></tr>
<tr><td> a </td><td> abcdef </td><td> abc </td></tr>
</table>
; LaTeX style
> (print-table '((abc abc abc) (abcdef ab abcdef) (a abcdef abc)) #:border-style 'latex)
\begin{tabular}{|l|l|l|}
\hline
abc & abc & abc \\
\hline
abcdef & ab & abcdef \\
\hline
a & abcdef & abc \\
\hline
\end{tabular}
; Aligning numbers (incorrectly then well)
> (print-table #:row-sep? '(#t #f ...) #:col-sep? '(#t #f ...) #:align '(left right ... center) #:->string (list ~a ; Name ~a (~r*) (~r* #:precision '(= 2)) (~r* #:notation 'exponential) ; Speed ~a) ; Unit ; The table: (map (λ (l) (pattern-list->list l 6)) `((Name Speed ... Unit) (Alice 10 ... "km/h") (Bob ,(sqrt 2) ... "m/s") (Charlie +inf.0 +nan.0 ... ... n/a) (light ,(* 299792458 (expt 10 3)) ... "mm/s"))))
┌───────┬─────────────────────────────────────────────────────────────────┐
│Name │ Speed Speed Speed Speed Unit│
├───────┼─────────────────────────────────────────────────────────────────┤
│Alice │ 10 10 10.00 1e+01 km/h│
│Bob │1.4142135623730951 1.414214 1.41 1.414214e+00 m/s │
│Charlie│ +inf.0 +nan.0 +inf.0 +nan.0 n/a │
│light │ 299792458000 299792458000 299792458000.00 2.997925e+11 mm/s│
└───────┴─────────────────────────────────────────────────────────────────┘
; Empty style and doubly repeating alignments
> (print-simple-table #:border-style 'empty #:align '(right left ... ...) (list (make-list 10 '*) (make-list 10 '**) (make-list 10 '***) (make-list 10 '****) (make-list 10 '*****) (make-list 10 "|")))
** ** ** ** **
**** **** **** **** ****
****** ****** ****** ****** ******
******** ******** ******** ******** ********
**************************************************
|| || || || ||
; Multiple separators
> (print-table (for/list ((i 6)) (for/list ((j 10)) (* (+ i 1) (+ j 1)))) #:row-sep? '(#t #f ... ...) #:col-sep? '(#t #f ... ...))
┌─┬─────┬─────┬─────┬─────┬──┐
│1│2 3 │4 5 │6 7 │8 9 │10│
├─┼─────┼─────┼─────┼─────┼──┤
│2│4 6 │8 10│12 14│16 18│20│
│3│6 9 │12 15│18 21│24 27│30│
├─┼─────┼─────┼─────┼─────┼──┤
│4│8 12│16 20│24 28│32 36│40│
│5│10 15│20 25│30 35│40 45│50│
├─┼─────┼─────┼─────┼─────┼──┤
│6│12 18│24 30│36 42│48 54│60│
└─┴─────┴─────┴─────┴─────┴──┘
1 Tables
procedure
(table->string table [ #:->string to-string #:border-style border-style #:framed? framed? #:row-sep? row-sep? #:col-sep? col-sep? #:align align #:row-align row-align]) → string? table : (listof list?)
to-string : (pattern-list-of (procedure-arity-includes/c 1)) = ~a border-style : border-style/c = 'single framed? : boolean? = #t row-sep? : (pattern-list-of boolean?) = #t col-sep? : (pattern-list-of boolean?) = #t align : (pattern-list-of (or/c 'left 'center 'right)) = 'left
row-align : (pattern-list-of (or/c 'top 'center 'bottom)) = 'top
The to-string procedure is used to convert cell values to strings, or a pattern-list of such procedures. Note that strings are not converted.
The border-style specifies the style of lines to be used in drawing the table.
When framed? is #true, a frame is drawn around the outside of the table.
The row-sep? and col-sep? arguments specify whether separators are added between rows or columns.
The align specification indicates how the contents of the cells are to be aligned within their cells. A single-symbol specification applies to all cells, or a list of symbols of the same length as the rows can be applied in order to specify the alignment of each column independently. When align is a list, it is trimmed to the length of the columns if it is too long, or the last element of the list is used for the remaining columns if it is too short.
The row-align specification indicates how the contents of the cells are aligned in a row, when cells are strings with multiple lines.
The to-string, align and row-align, row-sep? and col-sep? arguments accept pattern lists.
procedure
(simple-table->string table [ #:->string to-string #:border-style border-style #:framed? framed? #:row-sep? row-sep? #:col-sep? col-sep? #:align align #:row-align row-align]) → string? table : (listof list?)
to-string : (pattern-list-of (procedure-arity-includes/c 1)) = ~a border-style : border-style/c = 'single framed? : boolean? = #f row-sep? : (pattern-list-of boolean?) = #f col-sep? : (pattern-list-of boolean?) = #f align : (pattern-list-of (or/c 'left 'center 'right)) = 'left
row-align : (pattern-list-of (or/c 'top 'center 'bottom)) = 'top
> (displayln (simple-table->string #:align '(left right) '((a b c d e f gggg h) (123 456 77 54 1 5646547987 41 1) (111 22 3333 44 5 6 7 8888))))
a b c d e f gggg h
123 456 77 54 1 5646547987 41 1
111 22 3333 44 5 6 7 8888
procedure
(print-table table [ #:->string to-string #:border-style border-style #:framed? framed? #:row-sep? row-sep? #:col-sep? col-sep? #:align align #:row-align row-align]) → void? table : (listof list?)
to-string : (pattern-list-of (procedure-arity-includes/c 1)) = ~a border-style : border-style/c = 'single framed? : boolean? = #t row-sep? : (pattern-list-of boolean?) = #t col-sep? : (pattern-list-of boolean?) = #t align : (pattern-list-of (or/c 'left 'center 'right)) = 'left
row-align : (pattern-list-of (or/c 'top 'center 'bottom)) = 'top
procedure
(print-simple-table table [ #:->string to-string #:border-style border-style #:framed? framed? #:row-sep? row-sep? #:col-sep? col-sep? #:align align #:row-align row-align]) → void? table : (listof list?)
to-string : (pattern-list-of (procedure-arity-includes/c 1)) = ~a border-style : border-style/c = 'single framed? : boolean? = #f row-sep? : (pattern-list-of boolean?) = #f col-sep? : (pattern-list-of boolean?) = #f align : (pattern-list-of (or/c 'left 'center 'right)) = 'left
row-align : (pattern-list-of (or/c 'top 'center 'bottom)) = 'top
value
=
(or/c 'empty 'latex 'space 'space-single 'single 'rounded 'double 'heavy border-style1/c border-style2/c border-style-frame/c)
value
=
(list/c char? ; row sep (list/c string? string? string?) ; text line (list/c string? string? string?) ; top line (list/c string? string? string?) ; middle line (list/c string? string? string?) ; bottom line)
value
=
(list/c (list/c string? string? string? string?) ; top line (list/c string? string? string? string?) ; text line (list/c string? string? string? string?) ; middle line (list/c string? string? string? string?) ; bottom line)
> (print-table '((_ _ ___ _) (_ _ _ _) (_ "_\n__" _ _)) #:border-style '(("╭" "^" "┬" "╮") ("{" "." "│" "}") ("├" "─" "+" "┤") ("╰" "v" "┴" "╯")))
╭^^┬^^┬^^^^┬^╮
{_.│_.│____│_}
├──+──+────+─┤
{_.│_.│_...│_}
├──+──+────+─┤
{__│_.│_...│_}
{..│__│....│.}
╰vv┴vv┴vvvv┴v╯
value
=
(list/c (string-length=/c 5) ; top line (string-length=/c 5) ; text line (string-length=/c 5) ; middle line (string-length=/c 5) ; bottom line)
> (print-table '((abc abc abc) (abcdef ab abcdef) (a abcdef abc)) #:border-style '("╭─┬╮" "│.││" "├─┼┤" "╰─┴╯") #:align '(center))
╭──────┬──────┬──────╮
│.abc..│.abc..│.abc..│
├──────┼──────┼──────┤
│abcdef│..ab..│abcdef│
├──────┼──────┼──────┤
│..a...│abcdef│.abc..│
╰──────┴──────┴──────╯
procedure
((string-length=/c n) x) → boolean?
n : integer? x : any/c
2 Utilities
(require text-table/utils) | package: text-table |
2.1 Lists
procedure
((pattern-list-of pred?) x) → boolean?
pred? : (procedure-arity-includes/c 1) x : any/c
procedure
(pattern-list->list pat [ #:truncate-ok? truncate-ok?] result-length) → list? pat : (pattern-list-of any/c) truncate-ok? : any/c = #f result-length : exact-nonnegative-integer?
> (pattern-list->list 'a 3) '(a a a)
> (pattern-list->list '(a) 3) '(a a a)
> (pattern-list->list '(a b) 5) '(a b b b b)
> (pattern-list->list '(a b ...) 5) '(a b b b b)
> (pattern-list->list '(a b c ... ...) 10) '(a b c b c b c b c b)
> (pattern-list->list '(a b c d ... ... ... e f) 10) '(a b c d b c d b e f)
> (pattern-list->list '(a b c d ... ... ... e f) 2) Minimum length of list l exceeds n-elt '(a b c d ... ... ...
e f) 2
> (pattern-list->list '(a b c d ... ... ... e f) 2 #:truncate-ok? #t) '(a e)
> (transpose '((a b c) (1 2 3))) '((a 1) (b 2) (c 3))
procedure
(group-by-lengths l lengths) → (listof list?)
l : list? lengths : (listof exact-nonnegative-integer?)
> (group-by-lengths '(a b c d e f g) '(1 0 2 3 0 1)) '((a) () (b c) (d e f) () (g))
2.2 Strings
procedure
(string-repeat str len) → string?
str : string? len : exact-nonnegative-integer?
> (string-repeat "abc" 5) "abcab"
> (string-repeat "abc" 2) "ab"
procedure
(~r* [ #:sign sign #:base base #:precision precision #:notation notation #:format-exponent format-exponent #:min-width min-width #:pad-string pad-string #:groups groups #:group-sep group-sep #:decimal-sep decimal-sep]) → (any/c . -> . string?)
sign :
(or/c #f '+ '++ 'parens (let ([ind (or/c string? (list/c string? string?))]) (list/c ind ind ind))) = #f
base : (or/c (integer-in 2 36) (list/c 'up (integer-in 2 36))) = 10
precision :
(or/c exact-nonnegative-integer? (list/c '= exact-nonnegative-integer?)) = 6
notation :
(or/c 'positional 'exponential (-> rational? (or/c 'positional 'exponential))) = 'positional
format-exponent : (or/c #f string? (-> exact-integer? string?)) = #f min-width : exact-positive-integer? = 1 pad-string : non-empty-string? = " " groups : (non-empty-listof exact-positive-integer?) = '(3) group-sep : string? = "" decimal-sep : string? = "."
> (print-table #:->string (list ~a ; 1 (~r*) ; 2 (~r* #:notation 'exponential) ; 3 (~r* #:precision '(= 2)) ; 4 (good) (~r* #:notation 'exponential #:precision '(= 2)) ; 5 (good) (~r* #:min-width 10 #:pad-string ".")) ; 6 #:align '(right ...) #:row-sep? '(#f #t #f ...) (cons '("1" "2" "3" "4 (good)" "5 (good)" "6") (transpose (make-list 6 `(header 1111.11 22.222 3333000.0 4440000000000.0 ,(sqrt 2))))))
┌──────────────────┬─────────────┬────────────┬────────────────┬────────┬─────────────┐
│ 1│ 2│ 3│ 4 (good)│5 (good)│ 6│
│ header│ header│ header│ header│ header│ header....│
├──────────────────┼─────────────┼────────────┼────────────────┼────────┼─────────────┤
│ 1111.11│ 1111.11│ 1.11111e+03│ 1111.11│1.11e+03│ ...1111.11│
│ 22.222│ 22.222│ 2.2222e+01│ 22.22│2.22e+01│ ....22.222│
│ 3333000.0│ 3333000│ 3.333e+06│ 3333000.00│3.33e+06│ ...3333000│
│ 4440000000000.0│4440000000000│ 4.44e+12│4440000000000.00│4.44e+12│4440000000000│
│1.4142135623730951│ 1.414214│1.414214e+00│ 1.41│1.41e+00│ ..1.414214│
└──────────────────┴─────────────┴────────────┴────────────────┴────────┴─────────────┘