TextTable

Swift 5.0 License MIT License MIT Build Status

轻松地在 Swift 中打印文本表格。灵感来自 Python 的 tabulate 库。

即将到来的变更

查看关于即将到来的变更的详细信息

特性

要求

此软件包是为以下 Swift 版本编写并测试的

Apple Swift 版本 5.0

用法

使用 Swift Package Manager 安装 TextTable 作为项目的依赖项。

dependencies: [
    .package(
        url: "https://github.com/cfilipov/TextTable",
        .branch("master"))
]

首先,导入 TextTable

import TextTable

在整个示例中,将使用以下数据结构

struct Person {
    let name: String
    let age: Int
    let birhtday: Date
}

假设我们有一个 Person 集合,希望将其显示为表格。

let data = [
	Person(name: "Alice", age: 42, birhtday: Date()),
	Person(name: "Bob", age: 22, birhtday: Date()),
	Person(name: "Eve", age: 142, birhtday: Date())
]

配置 TextTable 实例

为您希望打印为表格的类型配置一个 TextTable 实例。 最低配置将需要一个值到列的映射。

let table = TextTable<Person> {
    [Column("Name" <- $0.name),
     Column("Age" <- $0.age),
     Column("Birthday" <- $0.birhtday)]
}

替代语法

<- 运算符只是语法糖。 如果您不想使用该运算符,则可以使用标记的参数。

let table = TextTable<Person> {
    [Column(title: "Name", value: $0.name),
     Column(title: "Age", value: $0.age),
     Column(title: "Birthday", value: $0.birhtday)]
}

打印表格

只需调用 print() 方法,传入一个 Person 集合。

table.print(data)
Name  Age Birthday
----- --- -------------------------
Alice 42  2016-08-13 19:21:54 +0000
Bob   22  2016-08-13 19:21:54 +0000
Eve   142 2016-08-13 19:21:54 +0000

获取字符串

您也可以通过调用 string(for:) 方法来获取渲染的表格作为字符串。

let s = table.string(for: data)

自定义表格样式

您可以选择使用 style: 参数指定表格样式。

table.print(data, style: Style.psql)
+-------+-----+---------------------------+
| Name  | Age | Birthday                  |
+-------+-----+---------------------------+
| Alice | 42  | 2016-08-13 08:12:58 +0000 |
| Bob   | 22  | 2016-08-13 08:12:58 +0000 |
| Eve   | 142 | 2016-08-13 08:12:58 +0000 |
+-------+-----+---------------------------+

在使用 string(for:) 方法时也可以指定样式。

let s = table.string(for: data, style: Style.psql)

有关支持的样式的完整列表,请参见下面的支持的样式

列特定的格式化器

您可以基于每列指定一个 格式化器。 在此示例中,使用 DateFormatter 自定义 Birthday 列的显示。

let df = DateFormatter()
dateFormatter.dateStyle = .medium

let table = TextTable<Person> {
    [Column("Name" <- $0.name),
     Column("Age" <- $0.age),
     Column("Birthday" <- $0.birhtday, formatter: df)]
}

table.print(data, style: Style.psql)
+-------+-----+--------------+
| Name  | Age | Birthday     |
+-------+-----+--------------+
| Alice | 42  | Aug 13, 2016 |
| Bob   | 22  | Aug 13, 2016 |
| Eve   | 142 | Aug 13, 2016 |
+-------+-----+--------------+

列宽

默认情况下,TextTable 将计算每列所需的宽度。 您还可以使用 width: 参数显式设置宽度。

let table = TextTable<Person> {
    [Column("Name" <- $0.name, width: 10),
     Column("Age" <- $0.age, width: 10)]
}

table.print(data, style: Style.psql)
+------------+------------+
| Name       | Age        |
+------------+------------+
| Alice      | 42         |
| Bob        | 22         |
| Eve        | 142        |
+------------+------------+

关于填充的说明

某些表格样式可能包括内容左侧和/或右侧的填充,width 参数不影响此填充。

截断

截断尾部

默认情况下,如果指定了宽度并且列的内容比宽度更宽,则文本将在尾部被截断 (.tail 截断模式)。

let table = TextTable<Person> {
	[Column("Name" <- $0.name, width: 4), // defaults to truncation: .tail
	 Column("Age" <- $0.age)]
}

table.print(data, style: testStyle)
+------+-----+
| Name | Age |
+------+-----+
| Ali… | 42  |
| Bob  | 22  |
| Eve  | 142 |
+------+-----+

截断头部

您还可以通过为 truncation: 参数指定 .head 来在文本字符串的头部截断。 如果不存在 width 参数,则 truncation 参数无效。

let table = TextTable<Person> {
	[Column("Name" <- $0.name, width: 4, truncate: .head),
	 Column("Age" <- $0.age)]
}

table.print(data, style: testStyle)
+------+-----+
| Name | Age |
+------+-----+
| …ice | 42  |
| Bob  | 22  |
| Eve  | 142 |
+------+-----+

截断错误

如果您希望在列的内容不适合指定的宽度时触发致命错误,则可以指定 .error 截断模式。

let table = TextTable<Person> {
	[Column("Name" <- $0.name, width: 4, truncate: .error),
	 Column("Age" <- $0.age)]
}

table.print(data, style: testStyle)

// fatal error: Truncation error

列对齐

默认情况下,所有列都将左对齐。 您可以分别设置每列的对齐方式。

let table = TextTable<Person> {
    [Column("Name" <- $0.name), // default: .left
     Column("Age" <- $0.age, align: .right)]
}

table.print(data, style: Style.psql)
+-------+-----+
| Name  | Age |
+-------+-----+
| Alice |  42 |
| Bob   |  22 |
| Eve   | 142 |
+-------+-----+

性能特征

默认情况下,TextTable 将计算未使用 width: 列参数指定显式宽度的每一列所需的宽度。 通过遍历表格的每一行两次来完成此计算:第一次计算最大宽度,第二次实际渲染表格。 此计算的开销可能不适用于非常大的表格。 如果您希望避免此计算,则必须为每一列指定宽度。

在下面的示例中,table1 将产生宽度计算的开销,因为其中一列没有显式宽度。 另一方面,table2 不会产生开销,因为所有列都具有显式宽度。

// This will still result in extra calculations
let table1 = TextTable<Person> {
    [Column("Name" <- $0.name),
     Column("Age" <- $0.age, width: 10)]
}
// This will skip the width calculations
let table2 = TextTable<Person> {
    [Column("Name" <- $0.name, width: 9),
     Column("Age" <- $0.age, width: 10)]
}

支持的样式

TextTable 支持与 tabulate 大多数相同的样式。

Plain (纯文本)

table.print(data, style: Style.plain)
Name  Age Birthday
Alice  42  8/13/16
Bob    22  8/13/16
Eve   142  8/13/16

Simple (简单)

simple 是默认样式。它对应于 Pandoc Markdown 扩展中的 simple_tables

table.print(data) // or:
table.print(data, style: Style.simple)
Name  Age Birthday
----- --- --------
Alice  42  8/13/16
Bob    22  8/13/16
Eve   142  8/13/16

Grid (网格)

grid 遵循 Emacs 的 table.el package 的约定。 它对应于 Pandoc Markdown 扩展中的 grid_tables

table.print(data, style: Style.grid)
+-------+-----+----------+
| Name  | Age | Birthday |
+=======+=====+==========+
| Alice |  42 |  8/13/16 |
+-------+-----+----------+
| Bob   |  22 |  8/13/16 |
+-------+-----+----------+
| Eve   | 142 |  8/13/16 |
+-------+-----+----------+

FancyGrid (精美网格)

table.print(data, style: Style.fancyGrid)
╒═══════╤═════╤══════════╕
│ Name  │ Age │ Birthday │
╞═══════╪═════╪══════════╡
│ Alice │  42 │  8/13/16 │
├───────┼─────┼──────────┤
│ Bob   │  22 │  8/13/16 │
├───────┼─────┼──────────┤
│ Eve   │ 142 │  8/13/16 │
╘═══════╧═════╧══════════╛

Psql (Psql 格式)

table.print(data, style: Style.psql)
+-------+-----+----------+
| Name  | Age | Birthday |
+-------+-----+----------+
| Alice |  42 |  8/13/16 |
| Bob   |  22 |  8/13/16 |
| Eve   | 142 |  8/13/16 |
+-------+-----+----------+

Pipe (管道)

pipe 遵循 PHP Markdown Extra extension 的约定。 它对应于 Pandoc 中的 pipe_tables。 此样式使用冒号来指示列对齐。

table.print(data, style: Style.pipe)
| Name  | Age | Birthday |
|:------|----:|---------:|
| Alice |  42 |  8/13/16 |
| Bob   |  22 |  8/13/16 |
| Eve   | 142 |  8/13/16 |

Org (Org 模式)

org 遵循 Emacs org-mode 的约定。

table.print(data, style: Style.org)
| Name  | Age | Birthday |
|-------+-----+----------|
| Alice |  42 |  8/13/16 |
| Bob   |  22 |  8/13/16 |
| Eve   | 142 |  8/13/16 |

Rst (Rst 格式)

rst 遵循 reStructuredText 样式的简单表格的约定。

table.print(data, style: Style.rst)
===== === ========
Name  Age Birthday
===== === ========
Alice  42  8/13/16
Bob    22  8/13/16
Eve   142  8/13/16
===== === ========

Html (Html 格式)

html 生成 HTML 表格 标记。

table.print(data, style: Style.html)
<table>
    <tr>
        <th style="text-align:left;">Name</th>
        <th style="text-align:center;">Age</th>
        <th style="text-align:right;">Birthday</th>
    </tr>
    <tr>
        <td>Alice</td>
        <td>42</td>
        <td>8/14/16</td>
    </tr>
    <tr>
        <td>Bob</td>
        <td>22</td>
        <td>8/14/16</td>
    </tr>
    <tr>
        <td>Eve</td>
        <td>142</td>
        <td>8/14/16</td>
    </tr>
</table>

Latex (Latex 格式)

latexLatex 生成一个 tabular 环境。

table.print(data, style: Style.latex)
\begin{tabular}{lll}
\hline
 Name & Age & Birthday \\
\hline
 Alice & 42 & 8/13/16 \\
 Bob & 22 & 8/13/16 \\
 Eve & 142 & 8/13/16 \\
\hline
\end{tabular}

自定义样式

您可以通过遵循 TextTableStyle 协议来创建自定义表格样式。

enum MyCustomStyle: TextTableStyle {
    // implement methods from TextTableStyle...
}

extension Style {
    static let custom = MyCustomStyle.self
}

table.print(data, style: Style.custom)

变更

更改列表可以在 CHANGELOG 中找到。

替代方案

其他 Swift 库具有类似的目的。

许可证

MIT 许可证

Copyright (c) 2016 Cristian Filipov

特此授予任何人免费获得本软件及其相关文档文件(“软件”)副本的许可,以便无限制地处理本软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或出售本软件副本的权利,并允许向其提供本软件的人员这样做,但须遵守以下条件:

上述版权声明和本许可声明应包含在本软件的所有副本或重要部分中。

本软件按“原样”提供,不附带任何形式的明示或暗示保证,包括但不限于适销性、适用于特定用途和不侵权的保证。 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是在合同诉讼、侵权诉讼还是其他诉讼中,由于与本软件或本软件的使用或其他处理有关而引起或与之相关的任何索赔、损害或其他责任负责。