NAME

Text::Table::Lite - Generate formatted tables from 2D arrays with multiline cells and multiple character encodings

表格转换文本工具,支持多种编码格式的中文,支持多行单元格。

VERSION

Version 1.03

SYNOPSIS

Basic Usage

use utf8;
use Text::Table::Lite qw(generate_table);

binmode STDOUT, ':encoding(UTF-8)';

my $rows = [
    ['姓名', '工作地点', '公司职位'],
    ["雷军",   "北京\n昌平", "小米\n集团董事会\n创始人"],
    ["马云",   "浙江\n杭州", "阿里巴巴\n董事会\n创始人"],
    ["刘强东", "北京\n亦庄", "京东\n集团董事会\n实控人"],
];

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'unicode',
    row_separator => 1,
);

print $table, "\n";

ASCII Borders

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'ascii',
    row_separator => 1,
);

print $table, "\n";

No Borders

my $table = generate_table(
    rows   => $rows,
    border => 'none',
    align  => ['left', 'left', 'left'],
);

print $table, "\n";

Column Alignment

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'unicode',
    row_separator => 1,
    align         => ['center', 'left', 'left'],
);

Column Width Limits and Wrapping

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'unicode',
    row_separator => 1,
    max_col_width => [6, 8, 10],
    wrap          => 1,
);

GBK Input and Output

use Encode qw(encode);
use Text::Table::Lite qw(generate_table);

my $rows = [
    [encode('GBK', '姓名'),
     encode('GBK', '工作地点'),
     encode('GBK', '公司职位')],

    [encode('GBK', '雷军'),
     encode('GBK', "北京\n昌平"),
     encode('GBK', "小米\n集团董事会\n创始人")],

    [encode('GBK', '马云'),
     encode('GBK', "浙江\n杭州"),
     encode('GBK', "阿里巴巴\n董事会\n创始人")],

    [encode('GBK', '刘强东'),
     encode('GBK', "北京\n亦庄"),
     encode('GBK', "京东\n集团董事会\n实控人")],
];

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'ascii',
    row_separator => 1,
    encoding      => 'GBK',
);

binmode STDOUT, ':raw';
print $table, "\n";

DESCRIPTION

Text::Table::Lite generates formatted text tables for terminal output, command-line applications, database utilities, administrative tools, log viewers, and other text-based interfaces.

The module is designed to handle Unicode text and multiline cell content while maintaining consistent table alignment. It calculates the display width of text rather than relying solely on the number of Perl characters or the number of encoded bytes.

The module supports the following features:

  • Unicode-aware display-width calculation for text containing Chinese and other wide characters.

  • Multiline cells containing newline characters.

  • Automatic padding of rows containing fewer cells than the table's column count.

  • Left, right, and center alignment for individual columns.

  • ASCII borders, Unicode borders, or borderless output.

  • Optional separators between data records.

  • Configurable header separator styles.

  • Optional maximum column widths, text wrapping, and truncation.

  • Configurable replacement text for undefined cell values.

  • Consistent input and output encoding through a single encoding parameter.

  • Strict encoding conversion that reports invalid input bytes and unrepresentable output characters instead of silently replacing them.

The module exports generate_table on request:

use Text::Table::Lite qw(generate_table);

The function returns the complete formatted table as a scalar. It does not print the table automatically.

FUNCTION

generate_table

my $table = generate_table(%options);

Generates a formatted table from an array reference containing rows of cell values.

The function accepts named options as key-value pairs and returns the formatted table as a scalar. Depending on the encoding option, the result is either a Perl character string or an encoded byte string.

Example:

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'unicode',
    row_separator => 1,
);

print $table, "\n";

Options should be supplied as key-value pairs. Unknown option names and invalid option values should not be relied upon; consult the module's validation behavior when integrating it into an application.

OPTIONS

The following options control the input data, table structure, formatting, and character encoding.

rows

Required.

rows => \@rows

An array reference containing the table rows. Each row must be represented by an array reference containing its cell values.

Each cell is expected to contain a scalar value. Cell values may be multiline strings containing newline characters. Undefined values are replaced with the string specified by null_value.

Example:

my $rows = [
    ['姓名', '工作地点', '公司职位'],
    ["雷军",   "北京\n昌平", "小米\n集团董事会\n创始人"],
    ["马云",   "浙江\n杭州", "阿里巴巴\n董事会\n创始人"],
    ["刘强东", "北京\n亦庄", "京东\n集团董事会\n实控人"],
];

my $table = generate_table(
    rows       => $rows,
    header_row => 1,
);

The number of columns is determined by the widest row in the input data. Rows with fewer cells are padded with empty cells so that all rows have the same number of columns.

For example:

my $rows = [
    ['姓名', '工作地点', '公司职位'],
    ['雷军', '北京'],
    ['马云', '浙江', '阿里巴巴', '额外字段'],
];

The widest row contains four cells. Consequently, the generated table contains four columns, and shorter rows are padded with empty cells.

Applications should normally provide a consistent number of columns in every row when a fixed table structure is required.

header_row

Optional. Default: 0.

header_row => 1

When true, the first row is treated as the table header. This setting affects header separator formatting when borders are enabled.

Example:

my $table = generate_table(
    rows       => $rows,
    header_row => 1,
    border     => 'unicode',
);

When header_row is false, all rows are treated as ordinary data rows.

When header_row is true, the first row is still part of the supplied rows array reference. The module does not create a header automatically.

The header is a formatting designation only. It does not change the input data or the column count.

border

Optional. Default: ascii.

border => 'ascii'
border => 'unicode'
border => 'none'

Selects the border style used to render the table.

ascii

Uses ASCII characters for table borders. This style is suitable for traditional terminals, restricted character sets, log files, and output that must remain compatible with legacy systems.

+----------+------------+------------+
| 姓名     | 工作地点   | 公司职位   |
+==========+============+============+
| 雷军     | 北京       | 小米       |
|          | 昌平       | 集团董事会 |
|          |            | 创始人     |
+----------+------------+------------+

The exact widths and separators depend on the input data and selected options.

unicode

Uses Unicode box-drawing characters to produce a visually structured table.

┌────────┬──────────┬────────────┐
│ 姓名   │ 工作地点 │ 公司职位   │
╞════════╪══════════╪════════════╡
│ 雷军   │ 北京     │ 小米       │
│        │ 昌平     │ 集团董事会 │
│        │          │ 创始人     │
├────────┼──────────┼────────────┤
│ 马云   │ 浙江     │ 阿里巴巴   │
│        │ 杭州     │ 董事会     │
│        │          │ 创始人     │
└────────┴──────────┴────────────┘

The actual output depends on the selected width, alignment, padding, and separator options.

Unicode borders require a terminal or output destination that can represent the selected Unicode characters. When using UTF-8 output, configure the output filehandle accordingly.

none

Omits table border characters. This is useful for compact command-line reports, plain-text output, and output that will be embedded in another format.

my $table = generate_table(
    rows   => $rows,
    border => 'none',
);

row_separator

Optional. Default: 0.

row_separator => 1

When true, inserts a separator between adjacent table records.

This option is particularly useful for database query results, command-line reports, and tables in which each logical record contains multiple physical lines.

For example, a cell such as:

"小米\n集团董事会\n创始人"

occupies three physical display lines, but it remains part of one logical record. The row separator is drawn after the complete record, not between the lines within that cell.

Example:

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'unicode',
    row_separator => 1,
);

When row_separator is false, ordinary data records are not separated by additional horizontal rules.

This option controls separators between records; it does not determine whether the table has an outer border or whether the header has a distinct separator.

header_border

Optional. Default: auto.

header_border => 'auto'
header_border => 'single'
header_border => 'double'

Controls the separator immediately below the header when header_row is true and the selected border style supports separators.

auto

Selects the default header separator for the chosen border style. With Unicode borders, the header separator uses the double-line style. With ASCII borders, it uses the corresponding ASCII separator style.

single

Uses a single-line header separator.

double

Uses a double-line header separator where supported by the selected border style.

Example:

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'unicode',
    header_border => 'double',
    row_separator => 1,
);

The header separator and data-record separators serve different purposes. header_border controls the line below the header, while row_separator controls separators between data records.

When header_row is false, there is no designated header row for header_border to separate.

padding

Optional. Default: 1.

padding => 1

Specifies the number of spaces placed on each side of a cell's content.

For example, with:

padding => 1

a cell has one space before its content and one space after it.

With:

padding => 2

the cell has two spaces on each side of its content.

Example:

my $table = generate_table(
    rows    => $rows,
    border  => 'unicode',
    padding => 2,
);

Increasing padding improves readability but also increases the total width of the table.

Use a small padding value for compact command-line output and a larger value for reports intended to be read interactively.

The value should be a non-negative integer. Negative values and other invalid values should not be used.

align

Optional.

align => \@alignment

An array reference specifying the horizontal alignment of each column. Each element should be one of:

left

Left-aligns the cell content.

Right-aligns the cell content.

center

Centers the cell content.

Example:

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'unicode',
    align         => ['center', 'left', 'left'],
    row_separator => 1,
);

The example centers the first column and left-aligns the second and third columns.

Columns without an explicitly supplied alignment default to left.

For example:

align => ['left', 'right']

sets the first column to left alignment and the second column to right alignment. Any remaining columns use the default alignment.

Alignment is applied to each physical line of a multiline cell. The calculated display width, rather than the number of bytes in the encoded string, is used to determine the amount of padding required.

max_col_width

Optional. Default: no maximum width.

max_col_width => 20

or:

max_col_width => [10, 20, 30]

Specifies the maximum content width of each column, measured in terminal display columns.

Three forms are supported by the option design:

  • Omit the option or use a value of 0 to indicate that no explicit maximum width is requested.

  • Supply a positive scalar to apply the same maximum content width to every column.

  • Supply an array reference to specify a separate width for each column.

Example:

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'unicode',
    max_col_width => 12,
    wrap          => 1,
);

Per-column example:

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'unicode',
    max_col_width => [8, 10, 12],
    wrap          => 1,
);

In the second example, the first column has a content-width limit of 8 display columns, the second column has a limit of 10, and the third column has a limit of 12.

The maximum width applies to the cell content, excluding the surrounding padding and border characters. Therefore, the overall column width can be greater than the configured content-width limit.

When a column has a non-zero maximum width, wrap determines whether content is wrapped or truncated.

The maximum width should be a non-negative integer. When an array reference is supplied, entries should correspond to the columns in the table. Applications should provide enough entries to describe all columns whose widths they need to control.

wrap

Optional. Default: 1.

wrap => 1
wrap => 0

Controls how content is handled when a column exceeds its configured maximum width.

wrap => 1

Enables wrapping for columns with a non-zero maximum width. Longer content is distributed across multiple physical lines so that it fits within the specified content width.

wrap => 0

Disables wrapping. Content that exceeds a configured maximum width is truncated according to the module's rendering behavior.

Example of wrapping:

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'unicode',
    max_col_width => [8, 8, 10],
    wrap          => 1,
);

Example of truncation:

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'unicode',
    max_col_width => [8, 8, 10],
    wrap          => 0,
);

When no maximum column width is configured, wrap does not by itself impose a width limit. Existing newline characters in cell values still represent explicit line breaks.

Wrapping and truncation should be tested with the actual text and terminal environment used by the application, especially when the text contains wide Unicode characters.

encoding

Optional. Default: characters.

encoding => 'characters'
encoding => 'UTF-8'
encoding => 'GBK'
encoding => 'GB2312'
encoding => 'Big5'

Specifies the encoding used for both input cell values and the returned table. Input and output encodings are intentionally kept identical.

The module uses Perl's Encode facilities to convert between encoded byte strings and Perl character strings.

characters

Indicates that input cell values are already-decoded Perl character strings and that the returned table should also be a character string.

This is the default and is generally recommended when the application uses use utf8 for source literals and performs I/O through correctly configured Perl filehandles.

Example:

use utf8;
use Text::Table::Lite qw(generate_table);

binmode STDOUT, ':encoding(UTF-8)';

my $table = generate_table(
    rows     => $rows,
    encoding => 'characters',
    border   => 'unicode',
);

print $table, "\n";

The characters setting does not encode the returned string into UTF-8 or any other byte representation. The output filehandle is responsible for encoding the character string when it is written.

Encoded byte strings

When encoding is set to a name recognized by Perl's Encode, input cell values are interpreted as byte strings in that encoding, and the returned table is encoded using the same encoding.

Example using GBK:

use Encode qw(encode);
use Text::Table::Lite qw(generate_table);

my $rows = [
    [encode('GBK', '姓名'),
     encode('GBK', '工作地点'),
     encode('GBK', '公司职位')],

    [encode('GBK', '雷军'),
     encode('GBK', "北京\n昌平"),
     encode('GBK', "小米\n集团董事会\n创始人")],
];

my $table = generate_table(
    rows     => $rows,
    encoding => 'GBK',
    border   => 'ascii',
);

binmode STDOUT, ':raw';
print $table, "\n";

In this example, the input strings are GBK-encoded byte strings, and the returned table is also a GBK-encoded byte string.

Do not configure the output filehandle to encode the result a second time. When the function returns encoded bytes, use an appropriate raw filehandle or write the bytes to a destination expecting that encoding.

Supported encoding names

The encoding name must be supported by the installed Perl Encode implementation. Common examples include UTF-8, GBK, GB2312, and Big5. The exact set of recognized aliases depends on the installed Perl distribution and its encoding tables.

Use the encoding name supported by the target Perl installation.

Strict conversion

Encoded mode uses strict conversion. Invalid input byte sequences cause an exception. Output characters that cannot be represented in the selected encoding also cause an exception.

For example, a Unicode character outside the representable range of GBK cannot be silently substituted when the conversion is strict.

Character strings and byte strings must not be mixed

In encoded mode, input values must be byte strings in the selected encoding. Do not pass already-decoded, UTF-8-flagged Perl character strings to an encoded mode that expects raw bytes.

In character mode, pass decoded Perl character strings rather than strings that still contain bytes in an external encoding.

Mixing these representations can cause decoding errors, incorrect text, or double encoding.

Border compatibility

Some encodings, including GBK and Big5, cannot represent all Unicode box-drawing characters used by Unicode table borders.

For such output encodings, use:

border => 'ascii'

when an ASCII border is sufficient and compatible with the target environment.

If Unicode borders are required, use a compatible Unicode output encoding such as UTF-8, together with an output destination that supports it.

null_value

Optional. Default: the empty string.

null_value => ''

Specifies the replacement value used for undefined cell values.

Example:

my $rows = [
    ['姓名', '工作地点', '公司职位'],
    ['雷军', undef,      '小米'],
    ['马云', '浙江杭州', undef],
];

my $table = generate_table(
    rows       => $rows,
    header_row => 1,
    border     => 'unicode',
    null_value => '(未提供)',
);

The replacement value is used instead of an undefined cell value. It does not replace an explicitly supplied empty string.

For example, undef and '' have different meanings:

['雷军', undef, '小米']
['马云', '',    '阿里巴巴']

With null_value => '(未提供)', the undefined cell is displayed as (未提供), while the explicitly empty cell remains empty.

The replacement value should use the same character or byte representation as the other cell values, according to the selected encoding mode.

OUTPUT AND DISPLAY WIDTH

The function returns the entire formatted table in one scalar. It does not automatically print a newline after the table.

Example:

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'unicode',
    row_separator => 1,
);

print $table, "\n";

The caller is responsible for adding a final newline if desired.

The module uses Unicode display-width calculation to align cell contents. This is important because the number of characters in a string is not always equal to the number of terminal columns it occupies.

For example, many Chinese characters occupy two terminal columns, while ordinary Latin letters usually occupy one. Counting bytes or Perl characters alone is therefore insufficient for reliable table alignment.

Actual rendering may also depend on the terminal emulator, font, Unicode width conventions, and output encoding. Applications that require consistent presentation across different environments should test their target terminals and output destinations.

COMMON USAGE PATTERNS

Database Query Results

my $rows = [
    ['ID', '姓名', '工作地点'],
    [1, '雷军',   "北京\n昌平"],
    [2, '马云',   "浙江\n杭州"],
    [3, '刘强东', "北京\n亦庄"],
];

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'unicode',
    row_separator => 1,
    align         => ['right', 'left', 'left'],
);

print $table, "\n";

This pattern is suitable for rendering database query results or reports in command-line applications.

Compact Output

my $table = generate_table(
    rows    => $rows,
    border  => 'none',
    padding => 0,
);

Use this style when minimizing output width is more important than visual separation.

Fixed-Width Reports

my $table = generate_table(
    rows          => $rows,
    header_row    => 1,
    border        => 'ascii',
    row_separator => 1,
    max_col_width => [12, 16, 20],
    wrap          => 1,
    padding       => 1,
);

This pattern is useful when output must fit within a known terminal width or when producing compact text reports.

Right-Aligned Numeric Columns

my $rows = [
    ['姓名', '记录数'],
    ['雷军', 123],
    ['马云', 4567],
];

my $table = generate_table(
    rows       => $rows,
    header_row => 1,
    border     => 'unicode',
    align      => ['left', 'right'],
);

Right alignment is commonly used for numeric values so that the digits are easier to compare vertically.

ERROR HANDLING

The function may throw an exception when it encounters invalid options or invalid encoding data.

Applications that need to recover from formatting errors should wrap the call in an eval block and inspect $@.

Example:

my $table;

eval {
    $table = generate_table(
        rows     => $rows,
        encoding => 'GBK',
        border   => 'ascii',
    );

    1;
} or do {
    my $error = $@ || 'Unknown table formatting error';
    warn "Unable to generate table: $error";
};

Do not assume that invalid input will always be silently corrected. In particular, encoded mode intentionally reports invalid byte sequences and output characters that cannot be represented in the requested encoding.

DEPENDENCIES

This module requires:

  • Unicode::GCString for Unicode-aware terminal display-width calculation.

  • Encode, included with standard Perl distributions, for character encoding conversion.

COMPATIBILITY NOTES

  • Use use utf8 when the Perl source file contains non-ASCII character literals and is saved in UTF-8.

  • use utf8 affects how Perl parses source text. It does not automatically decode arbitrary external byte strings.

  • For character-mode output, configure the output filehandle to match the destination encoding. For UTF-8 terminal output, this is commonly:

    binmode STDOUT, ':encoding(UTF-8)';
  • For encoded byte output, avoid applying another encoding layer to the already-encoded result.

  • When using GBK, GB2312, or Big5, ASCII borders are generally safer than Unicode box-drawing borders.

  • Unicode display widths can vary in some terminal environments, particularly for combining marks, emoji, and characters whose display width is ambiguous. Validate the final appearance in the target environment.

AUTHOR

H.Q. Wang

LICENSE

This module is free software. You may redistribute it and/or modify it under the same terms as Perl itself.

SEE ALSO

Encode, Unicode::GCString, perlunicode, perlfunc, perlop