Table utilities for deep copying, merging, sorting, searching, and rendering tables as strings or markdown pipe tables.
| Name | Signature |
|---|---|
render | render(t, indent) -> output |
print | print(t) |
copy | copy(source_table) -> copy |
merge | merge(defaults, options) -> merged |
get_value_by_ref | get_value_by_ref(t, ref) -> value |
alphanumsort | alphanumsort(o) -> sorted |
sort_keys | sort_keys(t) -> keys |
include_keys | include_keys(t, pattern) -> matched |
exclude_keys | exclude_keys(t, pattern) -> matched |
longest | longest(t) -> max |
contains | contains(t, element, fuzzy) -> index |
shuffle | shuffle(t) |
sort_by_str_len | sort_by_str_len(t) -> sorted |
parse_pipe_table_header | parse_pipe_table_header(header) -> name, align |
calc_table_maxes | calc_table_maxes(headers, t) -> maxes |
pipe_table | pipe_table(headers, t) -> lines |
empty | empty(t) -> is_empty |
render(
t,indent) ->output
Render a table as a formatted string
Produces a human-readable, indented representation of a table. Each
key–value pair is placed on its own line; nested tables are indented by
two spaces per level. Non-table values are formatted with tostring.
If t is not a table, returns tostring(t).
Example output:
{
name = "Alice",
scores = {
math = 95,
art = 88,
},
}
print(
t)
Print a table to stdout
copy(
source_table) ->copy
Create a deep copy of a table, handling cyclic references
Recursively copies all key–value pairs from source_table into a new
table. Cyclic references are detected and preserved (the copy will
contain the same cycle structure). Metatables are NOT copied.
merge(
defaults,options) ->merged
Deep merge an options table into a defaults table
Recursively merges options into defaults. When both values for
a key are tables, they are merged recursively. Otherwise the option
value overwrites the default. Modifies and returns defaults.
get_value_by_ref(
t,ref) ->value
Get a nested table value by dot-separated reference path
Traverses t following the keys named in ref, separated by ..
Returns nil as soon as any intermediate key is missing.
Example: get_value_by_ref(t, "server.host.port") is equivalent to
t.server → t.server.host → t.server.host.port.
alphanumsort(
o) ->sorted
Sort an array using natural alphanumeric ordering
Sorts t in place so that embedded numbers compare by value rather than
lexicographically (e.g., "file10" sorts after "file9"). Returns the
same array (modified in place).
Authored by Paul Kulchenko, creator of ZeroBrane Studio.
sort_keys(
t) ->keys
Get sorted keys of a table using natural alphanumeric ordering
Collects all keys from t into a new array and sorts them with
alphanumsort. Does not modify t. The returned array contains only
keys, not values.
include_keys(
t,pattern) ->matched
Filter an array to include only strings matching a pattern
Returns a new array containing only the string elements of t whose
value matches pattern (anchored at the start, i.e., ^pattern).
Non-string elements are silently skipped. Default pattern is ".*".
exclude_keys(
t,pattern) ->matched
Filter an array to exclude strings matching a pattern
Returns a new array containing the string elements of t that do NOT
match pattern (anchored at the start, i.e., ^pattern). Non-string
elements are silently skipped. Default pattern is ".*".
longest(
t) ->max
Get the UTF-8 length of the longest string in an array
Returns the display width of the longest string in the array, correctly handling multi-byte UTF-8 characters using utf.len.
contains(
t,element,fuzzy) ->index
Check if an array contains an element, with optional fuzzy matching
Searches for element in the array t. If fuzzy is true and both
element and array items are strings, performs pattern matching instead
of exact comparison.
shuffle(
t)
Shuffle an array in place using Fisher-Yates algorithm
Randomly shuffles the elements of the array t in place using the
Fisher-Yates algorithm. This modifies the original array.
sort_by_str_len(
t) ->sorted
Sort an array of strings by display length
Sorts the array of strings by their display width (handling multi-byte characters correctly) in ascending order. For equal display widths, strings are sorted lexicographically.
parse_pipe_table_header(
header) ->name,align
Parse a pipe table header definition with optional alignment
Splits a header string into a column name and an alignment specifier. Supported formats:
| Input | name | align |
|---|---|---|
"Name" | "Name" | "left" |
"Name:left" | "Name" | "left" |
"Name:l" | "Name" | "left" |
"Name:right" | "Name" | "right" |
"Name:r" | "Name" | "right" |
"Name:center" | "Name" | "center" |
"Name:c" | "Name" | "center" |
calc_table_maxes(
headers,t) ->maxes
Calculate maximum display widths for each column in a table
Returns a table mapping column index (1-based) to the maximum display
width of any cell in that column, including the header. Uses
utf.display_len for correct handling of wide characters (CJK, emoji).
headers is an array of header definition strings (see
parse_pipe_table_header). t is an array of rows, each row being an
array of cell values.
pipe_table(
headers,t) ->lines
Generate a markdown pipe table from headers and data
Returns an array of strings (one per line) forming a markdown pipe table.
headers is an array of header definitions (see parse_pipe_table_header).
t is an array of rows, each row being an array of cell values. Column
widths are computed by calc_table_maxes. Headers are center-aligned;
data cells follow the alignment declared in each header definition.
Example:
local lines = pipe_table(
{ "Name", "Age:right", "City:center" },
{
{ "Alice", 30, "New York" },
{ "Bob", 25, "Los Angeles" },
}
)
empty(
t) ->is_empty
Check if a table is empty (has no keys)
Returns true if the table has no keys (is empty), false otherwise. Note: This only checks for keys, not for nil values.